Merge pull request #260 from ejsd1989/issue-#242

Removes redundant null pointer checks checks
diff --git a/.gitignore b/.gitignore
index cb0347f..a2d6ca9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,7 +19,7 @@
 autom4te.cache
 
 # downloaded files
-gtest
+gmock
 
 # in-tree configure-generated files
 Makefile
@@ -43,16 +43,22 @@
 
 .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
@@ -73,3 +79,37 @@
 # 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/javac_middleman
+conformance/protoc_middleman
diff --git a/.travis.yml b/.travis.yml
index 93013b8..c0309fa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,74 @@
+sudo: required
+# Note: travis currently does not support listing more than one language so
+# this 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.
 language: cpp
-script: ./autogen.sh && ./configure && make distcheck
+os:
+  - linux
+  - osx
+# The Objective C build needs Xcode 7.0 or later.
+osx_image: xcode7.2
+script:
+  - ./travis.sh $CONFIG
+env:
+  - CONFIG=cpp
+  - CONFIG=cpp_distcheck
+  - CONFIG=csharp
+  - CONFIG=golang
+  - CONFIG=java_jdk6
+  - CONFIG=java_jdk7
+  - CONFIG=java_oracle7
+  - CONFIG=javanano_jdk6
+  - CONFIG=javanano_jdk7
+  - CONFIG=javanano_oracle7
+  - CONFIG=javascript
+  - CONFIG=python
+  - CONFIG=python_cpp
+  - CONFIG=ruby19
+  - CONFIG=ruby20
+  - CONFIG=ruby21
+  - CONFIG=ruby22
+  - CONFIG=jruby
+matrix:
+  exclude:
+    # It's nontrivial to programmatically install a new JDK from the command
+    # line on OS X, so we rely on testing on Linux for Java code.
+    - os: osx
+      env: CONFIG=java_jdk6
+    - os: osx
+      env: CONFIG=java_jdk7
+    - os: osx
+      env: CONFIG=java_oracle7
+    - os: osx
+      env: CONFIG=javanano_jdk6
+    - os: osx
+      env: CONFIG=javanano_jdk7
+    - os: osx
+      env: CONFIG=javanano_oracle7
+    # Requires installing mono, currently travis.sh is doing that with apt-get
+    # which doesn't work on OS X.
+    - os: osx
+      env: CONFIG=csharp
+    # Requires installing golang, currently travis.sh is doing that with apt-get
+    # which doesn't work on OS X.
+    - os: osx
+      env: CONFIG=golang
+  # Add into the matrix OS X tests of Objective C (needs Xcode, so it won't
+  # work on other platforms). These are split so it doesn't take as long to run.
+  include:
+    - os: osx
+      env: CONFIG=objectivec_ios
+    - os: osx
+      env: CONFIG=objectivec_osx
+  allow_failures:
+    # These currently do not work on OS X but are being worked on by @haberman.
+    - os: osx
+      env: CONFIG=ruby22
+    - os: osx
+      env: CONFIG=jruby
+    # Currently showing flake randomly, doesn't trace back to a single commit.
+    - os: osx
+      env: CONFIG=objectivec_ios
 notifications:
   email: false
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 18bdd09..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,486 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH := $(call my-dir)
-
-IGNORED_WARNINGS := -Wno-sign-compare -Wno-unused-parameter -Wno-sign-promo
-
-CC_LITE_SRC_FILES := \
-    src/google/protobuf/stubs/common.cc                              \
-    src/google/protobuf/stubs/once.cc                                \
-    src/google/protobuf/stubs/hash.cc                                \
-    src/google/protobuf/stubs/hash.h                                 \
-    src/google/protobuf/stubs/map-util.h                             \
-    src/google/protobuf/stubs/stl_util-inl.h                         \
-    src/google/protobuf/extension_set.cc                             \
-    src/google/protobuf/generated_message_util.cc                    \
-    src/google/protobuf/message_lite.cc                              \
-    src/google/protobuf/repeated_field.cc                            \
-    src/google/protobuf/wire_format_lite.cc                          \
-    src/google/protobuf/io/coded_stream.cc                           \
-    src/google/protobuf/io/coded_stream_inl.h                        \
-    src/google/protobuf/io/zero_copy_stream.cc                       \
-    src/google/protobuf/io/zero_copy_stream_impl_lite.cc
-
-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/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
-
-COMPILER_SRC_FILES :=  \
-    src/google/protobuf/descriptor.cc \
-    src/google/protobuf/descriptor.pb.cc \
-    src/google/protobuf/descriptor_database.cc \
-    src/google/protobuf/dynamic_message.cc \
-    src/google/protobuf/extension_set.cc \
-    src/google/protobuf/extension_set_heavy.cc \
-    src/google/protobuf/generated_message_reflection.cc \
-    src/google/protobuf/generated_message_util.cc \
-    src/google/protobuf/message.cc \
-    src/google/protobuf/message_lite.cc \
-    src/google/protobuf/reflection_ops.cc \
-    src/google/protobuf/repeated_field.cc \
-    src/google/protobuf/service.cc \
-    src/google/protobuf/text_format.cc \
-    src/google/protobuf/unknown_field_set.cc \
-    src/google/protobuf/wire_format.cc \
-    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 \
-    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_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/java/java_enum.cc \
-    src/google/protobuf/compiler/java/java_enum_field.cc \
-    src/google/protobuf/compiler/java/java_extension.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_helpers.cc \
-    src/google/protobuf/compiler/java/java_message.cc \
-    src/google/protobuf/compiler/java/java_message_field.cc \
-    src/google/protobuf/compiler/java/java_primitive_field.cc \
-    src/google/protobuf/compiler/java/java_service.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 \
-    src/google/protobuf/compiler/javamicro/javamicro_file.cc \
-    src/google/protobuf/compiler/javamicro/javamicro_generator.cc \
-    src/google/protobuf/compiler/javamicro/javamicro_helpers.cc \
-    src/google/protobuf/compiler/javamicro/javamicro_message.cc \
-    src/google/protobuf/compiler/javamicro/javamicro_message_field.cc \
-    src/google/protobuf/compiler/javamicro/javamicro_primitive_field.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_message.cc \
-    src/google/protobuf/compiler/javanano/javanano_message_field.cc \
-    src/google/protobuf/compiler/javanano/javanano_primitive_field.cc \
-    src/google/protobuf/compiler/python/python_generator.cc \
-    src/google/protobuf/io/coded_stream.cc \
-    src/google/protobuf/io/gzip_stream.cc \
-    src/google/protobuf/io/printer.cc \
-    src/google/protobuf/io/tokenizer.cc \
-    src/google/protobuf/io/zero_copy_stream.cc \
-    src/google/protobuf/io/zero_copy_stream_impl.cc \
-    src/google/protobuf/io/zero_copy_stream_impl_lite.cc \
-    src/google/protobuf/stubs/common.cc \
-    src/google/protobuf/stubs/hash.cc \
-    src/google/protobuf/stubs/once.cc \
-    src/google/protobuf/stubs/structurally_valid.cc \
-    src/google/protobuf/stubs/strutil.cc \
-    src/google/protobuf/stubs/substitute.cc
-
-# Java nano library (for device-side users)
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-java-nano
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := 8
-
-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)
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Java nano library (for host-side users)
-# =======================================================
-include $(CLEAR_VARS)
-
-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)
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-# Java micro library (for device-side users)
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-java-micro
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := 8
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Java micro library (for host-side users)
-# =======================================================
-include $(CLEAR_VARS)
-
-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)
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-# Java lite library (for device-side users)
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-java-lite
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := 8
-
-LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Java lite library (for host-side users)
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := host-libprotobuf-java-lite
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-# C++ lite library
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-cpp-lite
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CPP_EXTENSION := .cc
-
-LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES)
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/android \
-    $(LOCAL_PATH)/src
-
-# Define the header files to be copied
-#LOCAL_COPY_HEADERS := \
-#    src/google/protobuf/stubs/once.h \
-#    src/google/protobuf/stubs/common.h \
-#    src/google/protobuf/io/coded_stream.h \
-#    src/google/protobuf/generated_message_util.h \
-#    src/google/protobuf/repeated_field.h \
-#    src/google/protobuf/extension_set.h \
-#    src/google/protobuf/wire_format_lite_inl.h
-#
-#LOCAL_COPY_HEADERS_TO := $(LOCAL_MODULE)
-
-LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
-
-# These are the minimum versions and don't need to be update.
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SDK_VERSION := 8
-else
-# x86/mips support only available from API 9.
-LOCAL_SDK_VERSION := 9
-endif
-LOCAL_NDK_STL_VARIANT := stlport_static
-
-include $(BUILD_STATIC_LIBRARY)
-
-# C++ lite library (libc++ flavored for the platform)
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-cpp-lite
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CPP_EXTENSION := .cc
-
-LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES)
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/android \
-    $(LOCAL_PATH)/src
-
-LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
-
-include $(BUILD_SHARED_LIBRARY)
-
-# C++ full library
-# =======================================================
-protobuf_cc_full_src_files := \
-    $(CC_LITE_SRC_FILES)                                             \
-    src/google/protobuf/stubs/strutil.cc                             \
-    src/google/protobuf/stubs/strutil.h                              \
-    src/google/protobuf/stubs/substitute.cc                          \
-    src/google/protobuf/stubs/substitute.h                           \
-    src/google/protobuf/stubs/structurally_valid.cc                  \
-    src/google/protobuf/descriptor.cc                                \
-    src/google/protobuf/descriptor.pb.cc                             \
-    src/google/protobuf/descriptor_database.cc                       \
-    src/google/protobuf/dynamic_message.cc                           \
-    src/google/protobuf/extension_set_heavy.cc                       \
-    src/google/protobuf/generated_message_reflection.cc              \
-    src/google/protobuf/message.cc                                   \
-    src/google/protobuf/reflection_ops.cc                            \
-    src/google/protobuf/service.cc                                   \
-    src/google/protobuf/text_format.cc                               \
-    src/google/protobuf/unknown_field_set.cc                         \
-    src/google/protobuf/wire_format.cc                               \
-    src/google/protobuf/io/gzip_stream.cc                            \
-    src/google/protobuf/io/printer.cc                                \
-    src/google/protobuf/io/tokenizer.cc                              \
-    src/google/protobuf/io/zero_copy_stream_impl.cc                  \
-    src/google/protobuf/compiler/importer.cc                         \
-    src/google/protobuf/compiler/parser.cc
-
-# C++ full library - stlport version
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-cpp-full
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/android \
-    external/zlib \
-    $(LOCAL_PATH)/src
-
-# Define the header files to be copied
-#LOCAL_COPY_HEADERS := \
-#    src/google/protobuf/stubs/once.h \
-#    src/google/protobuf/stubs/common.h \
-#    src/google/protobuf/io/coded_stream.h \
-#    src/google/protobuf/generated_message_util.h \
-#    src/google/protobuf/repeated_field.h \
-#    src/google/protobuf/extension_set.h \
-#    src/google/protobuf/wire_format_lite_inl.h
-#
-#LOCAL_COPY_HEADERS_TO := $(LOCAL_MODULE)
-
-LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
-
-# These are the minimum versions and don't need to be update.
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SDK_VERSION := 8
-else
-# x86/mips support only available from API 9.
-LOCAL_SDK_VERSION := 9
-endif
-LOCAL_NDK_STL_VARIANT := stlport_static
-
-include $(BUILD_STATIC_LIBRARY)
-
-# C++ full library - Gnustl+rtti version
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-cpp-full-gnustl-rtti
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/android \
-    external/zlib \
-    $(LOCAL_PATH)/src
-
-LOCAL_CFLAGS := -frtti $(IGNORED_WARNINGS)
-LOCAL_SDK_VERSION := 14
-LOCAL_NDK_STL_VARIANT := gnustl_static
-
-include $(BUILD_STATIC_LIBRARY)
-
-# C++ full library - libc++ version for the platform
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotobuf-cpp-full
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/android \
-    external/zlib \
-    $(LOCAL_PATH)/src
-
-LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
-LOCAL_SHARED_LIBRARIES := libz
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Clean temp vars
-protobuf_cc_full_src_files :=
-
-
-# Android Protocol buffer compiler, aprotoc (host executable)
-# used by the build systems as $(PROTOC) defined in
-# build/core/config.mk
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := aprotoc
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(COMPILER_SRC_FILES)
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/android \
-    external/zlib \
-    $(LOCAL_PATH)/src
-
-LOCAL_STATIC_LIBRARIES += libz
-
-ifneq ($(HOST_OS),windows)
-LOCAL_LDLIBS := -lpthread
-endif
-
-LOCAL_CFLAGS := $(IGNORED_WARNINGS)
-
-include $(BUILD_HOST_EXECUTABLE)
-
-# To test java proto params build rules.
-# =======================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := aprotoc-test-nano-params
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-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
-
-
-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
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# To test Android-specific nanoproto features.
-# =======================================================
-include $(CLEAR_VARS)
-
-# Parcelable messages
-LOCAL_MODULE := android-nano-test-parcelable
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-
-LOCAL_SRC_FILES := src/google/protobuf/unittest_simple_nano.proto
-
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
-
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
-        parcelable_messages = true
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-
-# Parcelable and extendable messages
-LOCAL_MODULE := android-nano-test-parcelable-extendable
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-
-LOCAL_SRC_FILES := src/google/protobuf/unittest_extension_nano.proto
-
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
-
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
-        parcelable_messages = true, \
-        store_unknown_fields = true
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-
-# Test APK
-LOCAL_PACKAGE_NAME := NanoAndroidTest
-
-LOCAL_SDK_VERSION := 8
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/device/test/java/com/google/protobuf/nano)
-
-LOCAL_MANIFEST_FILE := java/src/device/test/AndroidManifest.xml
-
-LOCAL_STATIC_JAVA_LIBRARIES := libprotobuf-java-nano \
-        android-nano-test-parcelable \
-        android-nano-test-parcelable-extendable
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
-
-# 2.3.0 prebuilts for backwards compatibility.
-include $(LOCAL_PATH)/prebuilts/Android.mk
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..3cac4a8
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,649 @@
+# 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",
+]
+
+# Bazel should provide portable link_opts for pthread.
+LINK_OPTS = ["-lpthread"]
+
+load(
+    "protobuf",
+    "cc_proto_library",
+    "py_proto_library",
+    "internal_copied_filegroup",
+    "internal_protobuf_py_tests",
+)
+
+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 = 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 = 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]
+
+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_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_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/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_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
+################################################################################
+genrule(
+    name = "gen_well_known_protos_java",
+    srcs = WELL_KNOWN_PROTOS,
+    outs = [
+        "wellknown.srcjar"
+    ],
+    cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" +
+        " -Isrc $(SRCS) " +
+        " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar",
+    tools = [":protoc"],
+)
+
+java_library(
+    name = "protobuf_java",
+    srcs = glob([
+        "java/core/src/main/java/com/google/protobuf/*.java",
+    ]) + [
+        ":gen_well_known_protos_java",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+################################################################################
+# Python support
+################################################################################
+
+# Hack:
+# protoc generated files contain imports like:
+#   "from google.protobuf.xxx import yyy"
+# However, the sources files of the python runtime are not directly under
+# "google/protobuf" (they are under python/google/protobuf).  We workaround
+# this by copying runtime source files into the desired location to workaround
+# the import issue. Ideally py_library should support something similiar to the
+# "include" attribute in cc_library to inject the PYTHON_PATH for all libraries
+# that depend on the target.
+#
+# If you use python protobuf as a third_party library in your bazel managed
+# project:
+# 1) Please import the whole package to //google/protobuf in your
+# project. Otherwise, bazel disallows generated files out of the current
+# package, thus we won't be able to copy protobuf runtime files into
+# //google/protobuf/.
+# 2) The runtime also requires "six" for Python2/3 compatibility, please see the
+# WORKSPACE file and bind "six" to your workspace as well.
+internal_copied_filegroup(
+    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",
+        ],
+    ),
+    include = "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": ["//util/python: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",
+    ],
+    includes = [
+        "python/",
+        "src/",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = [
+        ":protobuf",
+    ] + select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//util/python:python_headers"],
+    }),
+)
+
+config_setting(
+    name = "use_fast_cpp_protos",
+    values = {
+        "define": "use_fast_cpp_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_extra_srcs = [":python_srcs"],
+    py_libs = ["//external:six"],
+    srcs_version = "PY2AND3",
+    visibility = ["//visibility:public"],
+)
+
+internal_copied_filegroup(
+    name = "python_test_srcs",
+    srcs = glob(
+        [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    include = "python",
+)
+
+py_proto_library(
+    name = "python_common_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = "",
+    protoc = ":protoc",
+    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",
+    deps = [":python_common_test_protos"],
+)
+
+py_library(
+    name = "python_tests",
+    srcs = [":python_test_srcs"],
+    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 ac42aa5..3023c81 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,270 @@
+2015-08-26 version 3.0.0-beta-1 (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.
+
+  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
@@ -115,7 +382,7 @@
 
     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 impelmented.
+    list are not implemented.
 
     A new notion "syntax" is introduced to specify whether a .proto file
     uses proto2 or proto3:
@@ -216,7 +483,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]
 
@@ -296,7 +563,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.
@@ -310,7 +577,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.
 
@@ -577,7 +844,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
@@ -591,7 +858,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/INSTALL.txt b/INSTALL.txt
deleted file mode 100644
index ce3b094..0000000
--- a/INSTALL.txt
+++ /dev/null
@@ -1,237 +0,0 @@
-This file contains detailed but generic information on building and
-installing the C++ part of this project.  For shorter instructions,
-as well as instructions for compiling and installing the Java or
-Python parts, see README.
-
-======================================================================
-
-Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
-Foundation, Inc.
-
-   This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-
-Basic Installation
-==================
-
-   These are generic installation instructions.
-
-   The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation.  It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions.  Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
-   It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring.  (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
-
-   If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release.  If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
-   The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'.  You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
-  1. `cd' to the directory containing the package's source code and type
-     `./configure' to configure the package for your system.  If you're
-     using `csh' on an old version of System V, you might need to type
-     `sh ./configure' instead to prevent `csh' from trying to execute
-     `configure' itself.
-
-     Running `configure' takes awhile.  While running, it prints some
-     messages telling which features it is checking for.
-
-  2. Type `make' to compile the package.
-
-  3. Optionally, type `make check' to run any self-tests that come with
-     the package.
-
-  4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
-     source code directory by typing `make clean'.  To also remove the
-     files that `configure' created (so you can compile the package for
-     a different kind of computer), type `make distclean'.  There is
-     also a `make maintainer-clean' target, but that is intended mainly
-     for the package's developers.  If you use it, you may have to get
-     all sorts of other programs in order to regenerate files that came
-     with the distribution.
-
-Compilers and Options
-=====================
-
-   Some systems require unusual options for compilation or linking that
-the `configure' script does not know about.  Run `./configure --help'
-for details on some of the pertinent environment variables.
-
-   You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment.  Here
-is an example:
-
-     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
-   *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
-   You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory.  To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'.  `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
-   If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory.  After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
-
-Installation Names
-==================
-
-   By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc.  You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
-   You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files.  If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
-   In addition, if you use an unusual directory layout you can give
-options like `--bindir=PATH' to specify different values for particular
-kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
-   If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
-   Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System).  The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
-   For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
-   There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on.  Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option.  TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
-     CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
-     OS KERNEL-OS
-
-   See the file `config.sub' for the possible values of each field.  If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
-   If you are _building_ compiler tools for cross-compiling, you should
-use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
-   If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
-   If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists.  Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
-   Variables not defined in a site shell script can be set in the
-environment passed to `configure'.  However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost.  In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'.  For example:
-
-     ./configure CC=/usr/local2/bin/gcc
-
-will cause the specified gcc to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-`configure' Invocation
-======================
-
-   `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
-     Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
-     Print the version of Autoconf used to generate the `configure'
-     script, and exit.
-
-`--cache-file=FILE'
-     Enable the cache: use and save the results of the tests in FILE,
-     traditionally `config.cache'.  FILE defaults to `/dev/null' to
-     disable caching.
-
-`--config-cache'
-`-C'
-     Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
-     Do not print messages saying which checks are being made.  To
-     suppress all normal output, redirect it to `/dev/null' (any error
-     messages will still be shown).
-
-`--srcdir=DIR'
-     Look for the package's source code in directory DIR.  Usually
-     `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options.  Run
-`configure --help' for more details.
-
diff --git a/LICENSE b/LICENSE
index f086efd..f028c82 100644
--- a/LICENSE
+++ b/LICENSE
@@ -5,11 +5,9 @@
     This file is copyrighted by Red Hat Inc.
 
   - Atomicops support for AIX/POWER, located in
-    src/google/protobuf/stubs/atomicops_internals_aix.h.
+    src/google/protobuf/stubs/atomicops_internals_power.h.
     This file is copyrighted by Bloomberg Finance LP.
 
-  - Andorid.mk, which is copyrighted by The Android Open Source Project.
-
 Copyright 2014, Google Inc.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/Makefile.am b/Makefile.am
index 1c03923..fbd27fc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,151 +8,333 @@
 # the right time.
 SUBDIRS = . src
 
-# Always include gtest in distributions.
-DIST_SUBDIRS = $(subdirs) src
+# Always include gmock in distributions.
+DIST_SUBDIRS = $(subdirs) src conformance
 
-# 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 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
 
-java_EXTRA_DIST=                                                             \
-  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/ExtensionLite.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/MapEntry.java                       \
-  java/src/main/java/com/google/protobuf/MapEntryLite.java                   \
-  java/src/main/java/com/google/protobuf/MapField.java                       \
-  java/src/main/java/com/google/protobuf/MapFieldLite.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/UnknownFieldSetLite.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/FieldPresenceTest.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/LazyFieldLiteTest.java              \
-  java/src/test/java/com/google/protobuf/LazyFieldTest.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/MapForProto2LiteTest.java           \
-  java/src/test/java/com/google/protobuf/MapForProto2Test.java               \
-  java/src/test/java/com/google/protobuf/MapTest.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/UnknownEnumValueTest.java           \
-  java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.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/field_presence_test.proto           \
-  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/map_for_proto2_lite_test.proto      \
-  java/src/test/java/com/google/protobuf/map_for_proto2_test.proto           \
-  java/src/test/java/com/google/protobuf/map_test.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_test2.proto        \
-  java/src/test/java/com/google/protobuf/outer_class_name_test3.proto        \
-  java/src/test/java/com/google/protobuf/outer_class_name_test.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/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/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/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/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/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/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          \
@@ -190,37 +372,185 @@
   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.txt                                                                     \
+  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_descriptors_proto.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/Descriptor.pbobjc.h                             \
+  objectivec/google/protobuf/Descriptor.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/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/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/_parameterized.py                          \
+  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                         \
@@ -232,54 +562,57 @@
   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/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/pyext/README                                        \
-  python/google/protobuf/pyext/cpp_message.py                                \
-  python/google/protobuf/pyext/descriptor.h                                  \
-  python/google/protobuf/pyext/descriptor.cc                                 \
-  python/google/protobuf/pyext/descriptor_pool.h                             \
-  python/google/protobuf/pyext/descriptor_pool.cc                            \
-  python/google/protobuf/pyext/descriptor_containers.h                       \
-  python/google/protobuf/pyext/descriptor_containers.cc                      \
-  python/google/protobuf/pyext/extension_dict.h                              \
-  python/google/protobuf/pyext/extension_dict.cc                             \
-  python/google/protobuf/pyext/message.h                                     \
-  python/google/protobuf/pyext/message.cc                                    \
-  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.h                \
-  python/google/protobuf/pyext/repeated_composite_container.cc               \
-  python/google/protobuf/pyext/repeated_scalar_container.h                   \
-  python/google/protobuf/pyext/repeated_scalar_container.cc                  \
-  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/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/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                                          \
@@ -294,53 +627,119 @@
   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.rb                                               \
-  ruby/tests/generated_code_test.rb
+  ruby/tests/generated_code_test.rb                                          \
+  ruby/travis-test.sh
 
-all_EXTRA_DIST=$(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST)
+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
 
-EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST)                                       \
-  autogen.sh                                                                 \
-  generate_descriptor_proto.sh                                               \
-  README.md                                                                  \
-  INSTALL.txt                                                                \
-  LICENSE                                                                    \
-  CONTRIBUTORS.txt                                                           \
-  CHANGES.txt                                                                \
-  config.h.include                                                           \
-  editors/README.txt                                                         \
-  editors/proto.vim                                                          \
-  editors/protobuf-mode.el                                                   \
-  vsprojects/config.h                                                        \
-  vsprojects/google/protobuf/stubs/pbconfig.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
+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/Protobuf.podspec b/Protobuf.podspec
new file mode 100644
index 0000000..02c8372
--- /dev/null
+++ b/Protobuf.podspec
@@ -0,0 +1,41 @@
+# 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/Descriptor.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 5ea6aff..ba9c589 100644
--- a/README.md
+++ b/README.md
@@ -1,188 +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://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 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 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..c3f18cc
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,28 @@
+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 = "gtest",
+  actual = "@gmock_archive//:gtest",
+)
+
+bind(
+  name = "gtest_main",
+  actual = "@gmock_archive//:gtest_main",
+)
+
+bind(
+  name = "six",
+  actual = "@six_archive//:six",
+)
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 08966c6..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,27 +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.7.0 from the web..."
-  curl -O https://googletest.googlecode.com/files/gtest-1.7.0.zip
-  unzip -q gtest-1.7.0.zip
-  rm gtest-1.7.0.zip
-  mv gtest-1.7.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/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
index d6cd032..16f6d67 100644
--- a/benchmarks/google_speed.proto
+++ b/benchmarks/google_speed.proto
@@ -1,3 +1,5 @@
+syntax = "proto2";
+
 package benchmarks;
 
 option java_outer_classname = "GoogleSpeed";
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
new file mode 100644
index 0000000..15ae457
--- /dev/null
+++ b/cmake/CMakeLists.txt
@@ -0,0 +1,151 @@
+# 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)
+  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..941f33d
--- /dev/null
+++ b/cmake/tests.cmake
@@ -0,0 +1,209 @@
+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_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/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_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.h.include b/config.h.include
deleted file mode 100644
index 0c557fb..0000000
--- a/config.h.include
+++ /dev/null
@@ -1,7 +0,0 @@
-HASH_MAP_CLASS
-HASH_MAP_H
-HASH_NAMESPACE
-HASH_SET_CLASS
-HASH_SET_H
-HAVE_HASH_MAP
-HAVE_HASH_SET
diff --git a/configure.ac b/configure.ac
index 14351a8..33a6c64 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,18 +12,21 @@
 # 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-alpha-3-pre],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.0.0-beta-2],[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 | java | python | javanano | ruby) ;;
+  all | cpp | csharp | java | python | javanano | objectivec | ruby | js) ;;
   *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
 esac
 AC_SUBST(DIST_LANG)
@@ -56,6 +59,7 @@
 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...])
@@ -146,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
@@ -157,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 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..a983ba3
--- /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()) {
+      // Empty.
+    }
+
+    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/Makefile.am b/conformance/Makefile.am
new file mode 100644
index 0000000..2a43113
--- /dev/null
+++ b/conformance/Makefile.am
@@ -0,0 +1,161 @@
+## 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.rb                                               \
+  com/google/protobuf/conformance/Conformance.java             \
+  conformance_pb2.py                                           \
+  Conformance.pbobjc.h                                         \
+  Conformance.pbobjc.m
+
+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        \
+  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)
+	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) )
+	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 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
+
+# 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_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..cd06567
--- /dev/null
+++ b/conformance/conformance_ruby.rb
@@ -0,0 +1,114 @@
+#!/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
+      test_message = Conformance::TestAllTypes.decode_json(request.json_payload)
+
+    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
+    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-cpp: request={request.to_json}, " \
+                                 "response={response.to_json}\n")
+  end
+
+  $test_count += 1
+
+  true
+end
+
+loop do
+  unless do_test_io
+    STDERR.puts('conformance-cpp: 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..1b2e7d9
--- /dev/null
+++ b/conformance/failure_list_ruby.txt
@@ -0,0 +1,337 @@
+# Many of the JSON tests are failing due to a simple bug:
+# fields are not camel-cased at all right now.  Once this
+# is fixed, this list should grow a lot shorter.
+
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.AllFieldAcceptNull.JsonOutput
+JsonInput.AllFieldAcceptNull.ProtobufOutput
+JsonInput.Any.JsonOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.Any.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.BoolFieldAllCapitalFalse
+JsonInput.BoolFieldAllCapitalTrue
+JsonInput.BoolFieldCamelCaseFalse
+JsonInput.BoolFieldCamelCaseTrue
+JsonInput.BoolFieldDoubleQuotedFalse
+JsonInput.BoolFieldDoubleQuotedTrue
+JsonInput.BoolFieldFalse.JsonOutput
+JsonInput.BoolFieldFalse.ProtobufOutput
+JsonInput.BoolFieldIntegerOne
+JsonInput.BoolFieldIntegerZero
+JsonInput.BoolFieldTrue.JsonOutput
+JsonInput.BoolFieldTrue.ProtobufOutput
+JsonInput.BoolMapEscapedKey.JsonOutput
+JsonInput.BoolMapEscapedKey.ProtobufOutput
+JsonInput.BoolMapField.JsonOutput
+JsonInput.BoolMapFieldKeyNotQuoted
+JsonInput.BoolMapField.ProtobufOutput
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.BytesField.JsonOutput
+JsonInput.BytesFieldNoPadding
+JsonInput.BytesField.ProtobufOutput
+JsonInput.BytesRepeatedField.JsonOutput
+JsonInput.BytesRepeatedField.ProtobufOutput
+JsonInput.DoubleFieldInfinity.JsonOutput
+JsonInput.DoubleFieldInfinityNotQuoted
+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.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNan.ProtobufOutput
+JsonInput.DoubleFieldNegativeInfinity.JsonOutput
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
+JsonInput.DoubleFieldQuotedValue.JsonOutput
+JsonInput.DoubleFieldQuotedValue.ProtobufOutput
+JsonInput.DoubleFieldTooLarge
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationHas3FractionalDigits.Validator
+JsonInput.DurationHas6FractionalDigits.Validator
+JsonInput.DurationHas9FractionalDigits.Validator
+JsonInput.DurationHasZeroFractionalDigit.Validator
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMaxValue.JsonOutput
+JsonInput.DurationMaxValue.ProtobufOutput
+JsonInput.DurationMinValue.JsonOutput
+JsonInput.DurationMinValue.ProtobufOutput
+JsonInput.DurationMissingS
+JsonInput.DurationRepeatedValue.JsonOutput
+JsonInput.DurationRepeatedValue.ProtobufOutput
+JsonInput.EnumField.JsonOutput
+JsonInput.EnumFieldNotQuoted
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumField.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.EnumRepeatedField.JsonOutput
+JsonInput.EnumRepeatedField.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldMask.JsonOutput
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldNameDuplicate
+JsonInput.FieldNameDuplicateDifferentCasing1
+JsonInput.FieldNameDuplicateDifferentCasing2
+JsonInput.FieldNameEscaped.JsonOutput
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameNotQuoted
+JsonInput.FieldNameWithMixedCases.JsonOutput
+JsonInput.FieldNameWithMixedCases.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.Validator
+JsonInput.FieldNameWithNumbers.JsonOutput
+JsonInput.FieldNameWithNumbers.ProtobufOutput
+JsonInput.FieldNameWithNumbers.Validator
+JsonInput.FloatFieldInfinity.JsonOutput
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldInfinity.ProtobufOutput
+JsonInput.FloatFieldMaxNegativeValue.JsonOutput
+JsonInput.FloatFieldMaxNegativeValue.ProtobufOutput
+JsonInput.FloatFieldMaxPositiveValue.JsonOutput
+JsonInput.FloatFieldMaxPositiveValue.ProtobufOutput
+JsonInput.FloatFieldMinNegativeValue.JsonOutput
+JsonInput.FloatFieldMinNegativeValue.ProtobufOutput
+JsonInput.FloatFieldMinPositiveValue.JsonOutput
+JsonInput.FloatFieldMinPositiveValue.ProtobufOutput
+JsonInput.FloatFieldNan.JsonOutput
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNan.ProtobufOutput
+JsonInput.FloatFieldNegativeInfinity.JsonOutput
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
+JsonInput.FloatFieldQuotedValue.JsonOutput
+JsonInput.FloatFieldQuotedValue.ProtobufOutput
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.HelloWorld.JsonOutput
+JsonInput.HelloWorld.ProtobufOutput
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldLeadingSpace
+JsonInput.Int32FieldLeadingZero
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMaxValue.JsonOutput
+JsonInput.Int32FieldMaxValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int32FieldMinValue.ProtobufOutput
+JsonInput.Int32FieldNegativeWithLeadingZero
+JsonInput.Int32FieldNotInteger
+JsonInput.Int32FieldNotNumber
+JsonInput.Int32FieldPlusSign
+JsonInput.Int32FieldStringValueEscaped.JsonOutput
+JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
+JsonInput.Int32FieldStringValue.JsonOutput
+JsonInput.Int32FieldStringValue.ProtobufOutput
+JsonInput.Int32FieldTooLarge
+JsonInput.Int32FieldTooSmall
+JsonInput.Int32FieldTrailingSpace
+JsonInput.Int32MapEscapedKey.JsonOutput
+JsonInput.Int32MapEscapedKey.ProtobufOutput
+JsonInput.Int32MapField.JsonOutput
+JsonInput.Int32MapFieldKeyNotQuoted
+JsonInput.Int32MapField.ProtobufOutput
+JsonInput.Int64FieldBeString.Validator
+JsonInput.Int64FieldMaxValue.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
+JsonInput.Int64FieldMaxValue.ProtobufOutput
+JsonInput.Int64FieldMinValue.JsonOutput
+JsonInput.Int64FieldMinValueNotQuoted.JsonOutput
+JsonInput.Int64FieldMinValueNotQuoted.ProtobufOutput
+JsonInput.Int64FieldMinValue.ProtobufOutput
+JsonInput.Int64FieldNotInteger
+JsonInput.Int64FieldNotNumber
+JsonInput.Int64FieldTooLarge
+JsonInput.Int64FieldTooSmall
+JsonInput.Int64MapEscapedKey.JsonOutput
+JsonInput.Int64MapEscapedKey.ProtobufOutput
+JsonInput.Int64MapField.JsonOutput
+JsonInput.Int64MapFieldKeyNotQuoted
+JsonInput.Int64MapField.ProtobufOutput
+JsonInput.JsonWithComments
+JsonInput.MapFieldKeyIsNull
+JsonInput.MapFieldValueIsNull
+JsonInput.MessageField.JsonOutput
+JsonInput.MessageField.ProtobufOutput
+JsonInput.MessageMapField.JsonOutput
+JsonInput.MessageMapField.ProtobufOutput
+JsonInput.MessageRepeatedField.JsonOutput
+JsonInput.MessageRepeatedField.ProtobufOutput
+JsonInput.OneofFieldDuplicate
+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.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldTrailingComma
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotMessage
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotMessage
+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.StringFieldEscape.JsonOutput
+JsonInput.StringFieldEscape.ProtobufOutput
+JsonInput.StringFieldInvalidEscape
+JsonInput.StringField.JsonOutput
+JsonInput.StringFieldNotAString
+JsonInput.StringField.ProtobufOutput
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldSurrogatePair.ProtobufOutput
+JsonInput.StringFieldUnicodeEscape.JsonOutput
+JsonInput.StringFieldUnicodeEscape.ProtobufOutput
+JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
+JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
+JsonInput.StringFieldUnicode.JsonOutput
+JsonInput.StringFieldUnicode.ProtobufOutput
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.StringFieldUnterminatedEscape
+JsonInput.StringFieldUppercaseEscapeLetter
+JsonInput.StringRepeatedField.JsonOutput
+JsonInput.StringRepeatedField.ProtobufOutput
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampHas3FractionalDigits.Validator
+JsonInput.TimestampHas6FractionalDigits.Validator
+JsonInput.TimestampHas9FractionalDigits.Validator
+JsonInput.TimestampHasZeroFractionalDigit.Validator
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.TimestampJsonInputLowercaseZ
+JsonInput.TimestampJsonInputMissingT
+JsonInput.TimestampJsonInputMissingZ
+JsonInput.TimestampJsonInputTooLarge
+JsonInput.TimestampJsonInputTooSmall
+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.TrailingCommaInAnObject
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Uint32FieldMaxValue.JsonOutput
+JsonInput.Uint32FieldMaxValue.ProtobufOutput
+JsonInput.Uint32FieldNotInteger
+JsonInput.Uint32FieldNotNumber
+JsonInput.Uint32FieldTooLarge
+JsonInput.Uint32MapField.JsonOutput
+JsonInput.Uint32MapFieldKeyNotQuoted
+JsonInput.Uint32MapField.ProtobufOutput
+JsonInput.Uint64FieldBeString.Validator
+JsonInput.Uint64FieldMaxValue.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
+JsonInput.Uint64FieldMaxValue.ProtobufOutput
+JsonInput.Uint64FieldNotInteger
+JsonInput.Uint64FieldNotNumber
+JsonInput.Uint64FieldTooLarge
+JsonInput.Uint64MapField.JsonOutput
+JsonInput.Uint64MapFieldKeyNotQuoted
+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
+JsonInput.WrapperTypesWithNullValue.JsonOutput
+JsonInput.WrapperTypesWithNullValue.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..07ea90a
--- /dev/null
+++ b/csharp/.gitignore
@@ -0,0 +1,35 @@
+#
+# 	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
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/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..9899097
--- /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
+cd $(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..989b3dc
--- /dev/null
+++ b/csharp/protos/unittest_issues.proto
@@ -0,0 +1,119 @@
+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;
+  }
+  
+}
\ No newline at end of file
diff --git a/csharp/src/AddressBook/AddPerson.cs b/csharp/src/AddressBook/AddPerson.cs
new file mode 100644
index 0000000..6eeb9f6
--- /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..166dd49
--- /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 {
+        MOBILE = 0,
+        HOME = 1,
+        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_ = global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE;
+        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 != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) 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 != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) {
+            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 != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) {
+            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 != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) {
+            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..3979430
--- /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..7d85d28
--- /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 {
+    UNSPECIFIED = 0,
+    PROTOBUF = 1,
+    JSON = 2,
+  }
+
+  public enum ForeignEnum {
+    FOREIGN_FOO = 0,
+    FOREIGN_BAR = 1,
+    FOREIGN_BAZ = 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_ = global::Conformance.WireFormat.UNSPECIFIED;
+    /// <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 != global::Conformance.WireFormat.UNSPECIFIED) 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 != global::Conformance.WireFormat.UNSPECIFIED) {
+        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 != global::Conformance.WireFormat.UNSPECIFIED) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RequestedOutputFormat);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ConformanceRequest other) {
+      if (other == null) {
+        return;
+      }
+      if (other.RequestedOutputFormat != global::Conformance.WireFormat.UNSPECIFIED) {
+        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_ = global::Conformance.TestAllTypes.Types.NestedEnum.FOO;
+    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_ = global::Conformance.ForeignEnum.FOREIGN_FOO;
+    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 != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) hash ^= OptionalNestedEnum.GetHashCode();
+      if (OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) 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 != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) {
+        output.WriteRawTag(168, 1);
+        output.WriteEnum((int) OptionalNestedEnum);
+      }
+      if (OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) {
+        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 != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OptionalNestedEnum);
+      }
+      if (OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) {
+        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 != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) {
+        OptionalNestedEnum = other.OptionalNestedEnum;
+      }
+      if (other.OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) {
+        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 {
+        FOO = 0,
+        BAR = 1,
+        BAZ = 2,
+        /// <summary>
+        ///  Intentionally negative.
+        /// </summary>
+        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..f3f7e29
--- /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..6ae0211
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
@@ -0,0 +1,530 @@
+#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 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));

+        }

+    }

+}
\ 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..3297fe8
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
@@ -0,0 +1,391 @@
+#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);

+            }

+        }

+    }

+}
\ 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..38ba227
--- /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.FOREIGN_BAZ, "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..14cc6d1
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
@@ -0,0 +1,715 @@
+#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.FOREIGN_UNSPECIFIED, message.SingleForeignEnum);

+            Assert.IsNull(message.SingleForeignMessage);

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

+            Assert.IsNull(message.SingleImportMessage);

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

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

+            Assert.AreEqual(TestAllTypes.Types.NestedEnum.NESTED_ENUM_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.FOREIGN_BAR,

+                SingleForeignMessage = new ForeignMessage { C = 10 },

+                SingleImportEnum = ImportEnum.IMPORT_BAZ,

+                SingleImportMessage = new ImportMessage { D = 20 },

+                SingleInt32 = 100,

+                SingleInt64 = 3210987654321,

+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO,

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

+                SinglePublicImportMessage = new PublicImportMessage { E = 54 },

+                SingleSfixed32 = -123,

+                SingleSfixed64 = -12345678901234,

+                SingleSint32 = -456,

+                SingleSint64 = -12345678901235,

+                SingleString = "test",

+                SingleUint32 = uint.MaxValue,

+                SingleUint64 = ulong.MaxValue

+            };

+

+            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.FOREIGN_FOO, ForeignEnum.FOREIGN_BAR },

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

+                RepeatedImportEnum = { ImportEnum.IMPORT_BAZ, ImportEnum.IMPORT_ENUM_UNSPECIFIED },

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

+                RepeatedInt32 = { 100, 200 },

+                RepeatedInt64 = { 3210987654321, long.MaxValue },

+                RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.NEG },

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

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

+                RepeatedSfixed32 = { -123, 123 },

+                RepeatedSfixed64 = { -12345678901234, 12345678901234 },

+                RepeatedSint32 = { -456, 100 },

+                RepeatedSint64 = { -12345678901235, 123 },

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

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

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

+            };

+

+            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.MAP_ENUM_BAR },

+                    { 2000, MapEnum.MAP_ENUM_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 ExtraEndGroupSkipped()

+        {

+            var message = SampleMessages.CreateFullTestAllTypes();

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+

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

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

+            output.WriteFixed32(123);

+

+            output.Flush();

+

+            stream.Position = 0;

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

+            Assert.AreEqual(new TestAllTypes { SingleFixed32 = 123 }, parsed);

+        }

+

+        [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));

+        }

+    }

+}

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..a035003
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/IssuesTest.cs
@@ -0,0 +1,63 @@
+#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());

+        }

+    }

+}

diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
new file mode 100644
index 0000000..4245504
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
@@ -0,0 +1,518 @@
+#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.FOREIGN_BAR,
+                SingleForeignMessage = new ForeignMessage { C = 10 },
+                SingleImportEnum = ImportEnum.IMPORT_BAZ,
+                SingleImportMessage = new ImportMessage { D = 20 },
+                SingleInt32 = 100,
+                SingleInt64 = 3210987654321,
+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO,
+                SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 },
+                SinglePublicImportMessage = new PublicImportMessage { E = 54 },
+                SingleSfixed32 = -123,
+                SingleSfixed64 = -12345678901234,
+                SingleSint32 = -456,
+                SingleSint64 = -12345678901235,
+                SingleString = "test\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.FOREIGN_BAZ, (ForeignEnum) 100, ForeignEnum.FOREIGN_FOO } };
+            AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void UnknownEnumValueNumeric_MapField()
+        {
+            var message = new TestMap { MapInt32Enum = { { 1, MapEnum.MAP_ENUM_FOO }, { 2, (MapEnum) 100 }, { 3, MapEnum.MAP_ENUM_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.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 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..d21da58
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
@@ -0,0 +1,925 @@
+#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_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.FOREIGN_BAR)]
+        [TestCase("5", ForeignEnum.FOREIGN_BAR)]
+        [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 + '"';
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
new file mode 100644
index 0000000..a0a6222
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
@@ -0,0 +1,409 @@
+#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("{{", 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..086a4e9
--- /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.FOREIGN_FOO, 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..936e41c
--- /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.FOREIGN_FOO);
+            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.FOREIGN_FOO,
+                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..8a9c7f8
--- /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.FOREIGN_BAR,
+                SingleForeignMessage = new ForeignMessage { C = 10 },
+                SingleImportEnum = ImportEnum.IMPORT_BAZ,
+                SingleImportMessage = new ImportMessage { D = 20 },
+                SingleInt32 = 100,
+                SingleInt64 = 3210987654321,
+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO,
+                SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 },
+                SinglePublicImportMessage = new PublicImportMessage { E = 54 },
+                SingleSfixed32 = -123,
+                SingleSfixed64 = -12345678901234,
+                SingleSint32 = -456,
+                SingleSint64 = -12345678901235,
+                SingleString = "test",
+                SingleUint32 = 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.FOREIGN_FOO, ForeignEnum.FOREIGN_BAR },
+                RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } },
+                RepeatedImportEnum = { ImportEnum.IMPORT_BAZ, ImportEnum.IMPORT_ENUM_UNSPECIFIED },
+                RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } },
+                RepeatedInt32 = { 100, 200 },
+                RepeatedInt64 = { 3210987654321, 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"                
+            };
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/TestCornerCases.cs b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs
new file mode 100644
index 0000000..03fa185
--- /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.NEGATIVE_ENUM_ZERO, NegativeEnum.MinusOne, NegativeEnum.FiveBelow },

+                PackedValues = { NegativeEnum.NEGATIVE_ENUM_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..27c0478
--- /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 {
+    MAP_ENUM_FOO = 0,
+    MAP_ENUM_BAR = 1,
+    MAP_ENUM_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 {
+        TYPE_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..7b824dc
--- /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 {
+    IMPORT_ENUM_UNSPECIFIED = 0,
+    IMPORT_FOO = 7,
+    IMPORT_BAR = 8,
+    IMPORT_BAZ = 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..16176a3
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
@@ -0,0 +1,1406 @@
+// 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",
+            "KlUKDE5lZ2F0aXZlRW51bRIWChJORUdBVElWRV9FTlVNX1pFUk8QABIWCglG",
+            "aXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD///////////8BKi4K",
+            "DkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcKA29uZRAB",
+            "Qh9IAaoCGlVuaXRUZXN0Lklzc3Vlcy5UZXN0UHJvdG9zYgZwcm90bzM="));
+      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)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  public enum NegativeEnum {
+    NEGATIVE_ENUM_ZERO = 0,
+    FiveBelow = -5,
+    MinusOne = -1,
+  }
+
+  public enum DeprecatedEnum {
+    DEPRECATED_ZERO = 0,
+    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_ = global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO;
+    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 != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) 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 != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) {
+        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 != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) {
+        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 != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) {
+        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_ = global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO;
+    [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 != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) 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 != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) {
+        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 != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) {
+        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 != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) {
+        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;
+          }
+        }
+      }
+    }
+
+  }
+
+  #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..d846544
--- /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 {
+    FOREIGN_UNSPECIFIED = 0,
+    FOREIGN_FOO = 4,
+    FOREIGN_BAR = 5,
+    FOREIGN_BAZ = 6,
+  }
+
+  /// <summary>
+  ///  Test an enum that has multiple values with the same number.
+  /// </summary>
+  public enum TestEnumWithDupValue {
+    TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED = 0,
+    FOO1 = 1,
+    BAR1 = 2,
+    BAZ = 3,
+    FOO2 = 1,
+    BAR2 = 2,
+  }
+
+  /// <summary>
+  ///  Test an enum with large, unordered values.
+  /// </summary>
+  public enum TestSparseEnum {
+    TEST_SPARSE_ENUM_UNSPECIFIED = 0,
+    SPARSE_A = 123,
+    SPARSE_B = 62374,
+    SPARSE_C = 12589234,
+    SPARSE_D = -15,
+    SPARSE_E = -53452,
+    /// <summary>
+    ///  In proto3, value 0 must be the first one specified
+    ///  SPARSE_F = 0;
+    /// </summary>
+    SPARSE_G = 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_ = global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED;
+    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_ = global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED;
+    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_ = global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED;
+    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 != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) hash ^= SingleNestedEnum.GetHashCode();
+      if (SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) hash ^= SingleForeignEnum.GetHashCode();
+      if (SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) 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 != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) {
+        output.WriteRawTag(168, 1);
+        output.WriteEnum((int) SingleNestedEnum);
+      }
+      if (SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) {
+        output.WriteRawTag(176, 1);
+        output.WriteEnum((int) SingleForeignEnum);
+      }
+      if (SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) {
+        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 != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleNestedEnum);
+      }
+      if (SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleForeignEnum);
+      }
+      if (SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) {
+        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 != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) {
+        SingleNestedEnum = other.SingleNestedEnum;
+      }
+      if (other.SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) {
+        SingleForeignEnum = other.SingleForeignEnum;
+      }
+      if (other.SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) {
+        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 {
+        NESTED_ENUM_UNSPECIFIED = 0,
+        FOO = 1,
+        BAR = 2,
+        BAZ = 3,
+        /// <summary>
+        ///  Intentionally negative.
+        /// </summary>
+        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_ = global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED;
+    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 != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) 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 != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) {
+        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 != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) {
+        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 != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) {
+        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_ = global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED;
+    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 != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) hash ^= SparseEnum.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) SparseEnum);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SparseEnum);
+      }
+      return size;
+    }
+
+    public void MergeFrom(SparseEnumMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) {
+        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..f3593e5
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
@@ -0,0 +1,89 @@
+#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 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 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..a2c833f
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
@@ -0,0 +1,382 @@
+#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.
+        [Test]
+        public void MergingCornerCase()
+        {
+            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.
+            Assert.AreEqual(5, message.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..69ce9a4
--- /dev/null
+++ b/csharp/src/Google.Protobuf.sln
@@ -0,0 +1,56 @@
+Microsoft Visual Studio Solution File, Format Version 12.00

+# Visual Studio 2013

+VisualStudioVersion = 12.0.31101.0

+MinimumVisualStudioVersion = 10.0.40219.1

+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..91bed8e
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -0,0 +1,1221 @@
+#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

+    {

+        /// <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 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 CodedInputStream reading data from the given stream.

+        /// </summary>

+        public CodedInputStream(Stream input) : this(input, new byte[BufferSize], 0, 0)

+        {

+            ProtoPreconditions.CheckNotNull(input, "input");

+        }

+

+        /// <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; } }

+

+        #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>

+        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();

+                    break;

+                case WireFormat.WireType.EndGroup:

+                    // Just ignore; there's no data following the tag.

+                    break;

+                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()

+        {

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

+            do

+            {

+                tag = ReadTag();

+                if (tag == 0)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                // This recursion will allow us to handle nested groups.

+                SkipLastField();

+            } while (WireFormat.GetTagWireType(tag) != WireFormat.WireType.EndGroup);

+            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..d6355f0
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs
@@ -0,0 +1,708 @@
+#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

+    {

+        // "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 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;

+        }

+

+        private CodedOutputStream(Stream output, byte[] buffer)

+        {

+            this.output = output;

+            this.buffer = buffer;

+            this.position = 0;

+            this.limit = buffer.Length;

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream.

+        /// </summary>

+        public CodedOutputStream(Stream output) : this(output, DefaultBufferSize)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream and uses

+        /// the specified buffer size.

+        /// </summary>

+        public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize])

+        {

+        }    

+        #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 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.");

+                }

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
new file mode 100644
index 0000000..90a5ff1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -0,0 +1,759 @@
+#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.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 builder = new StringBuilder();
+            JsonFormatter.Default.WriteDictionary(builder, this);
+            return builder.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..1cde03b
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -0,0 +1,567 @@
+#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.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 builder = new StringBuilder();
+            JsonFormatter.Default.WriteList(builder, this);
+            return builder.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..ef524ba
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -0,0 +1,167 @@
+<?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\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..d530254
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
@@ -0,0 +1,66 @@
+<?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-beta2</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.Runtime" version="4.0.0" />
+        <dependency id="System.Runtime.Extensions" version="4.0.0" />
+        <dependency id="System.Text.Encoding" version="4.0.0" />
+        <dependency id="System.Text.RegularExpressions" version="4.0.0" />
+      </group>
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" />
+    <file src="**\*.cs" target="src" />
+    <file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
+  </files>
+</package>
\ No newline at end of file
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..60f61fc
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -0,0 +1,865 @@
+#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.Linq;
+using System.Collections.Generic;
+
+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)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            StringBuilder builder = new StringBuilder();
+            if (message.Descriptor.IsWellKnownType)
+            {
+                WriteWellKnownTypeValue(builder, message.Descriptor, message);
+            }
+            else
+            {
+                WriteMessage(builder, message);
+            }
+            return builder.ToString();
+        }
+
+        /// <summary>
+        /// Converts a message to JSON for diagnostic purposes with no extra context.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
+        /// formatter in its handling of <see cref="Any"/>. As no type registry is available
+        /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
+        /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
+        /// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
+        /// </para>
+        /// <para>The value returned by this method is only designed to be used for diagnostic
+        /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
+        /// by other Protocol Buffer implementations.</para>
+        /// </remarks>
+        /// <param name="message">The message to format for diagnostic purposes.</param>
+        /// <returns>The diagnostic-only JSON representation of the message</returns>
+        public static string ToDiagnosticString(IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            return diagnosticFormatter.Format(message);
+        }
+
+        private void WriteMessage(StringBuilder builder, IMessage message)
+        {
+            if (message == null)
+            {
+                WriteNull(builder);
+                return;
+            }
+            if (DiagnosticOnly)
+            {
+                ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage;
+                if (customDiagnosticMessage != null)
+                {
+                    builder.Append(customDiagnosticMessage.ToDiagnosticString());
+                    return;
+                }
+            }
+            builder.Append("{ ");
+            bool writtenFields = WriteMessageFields(builder, message, false);
+            builder.Append(writtenFields ? " }" : "}");
+        }
+
+        private bool WriteMessageFields(StringBuilder builder, 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)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                WriteString(builder, ToCamelCase(accessor.Descriptor.Name));
+                builder.Append(NameValueSeparator);
+                WriteValue(builder, 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(StringBuilder builder)
+        {
+            builder.Append("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(StringBuilder builder, object value)
+        {
+            if (value == null)
+            {
+                WriteNull(builder);
+            }
+            else if (value is bool)
+            {
+                builder.Append((bool) value ? "true" : "false");
+            }
+            else if (value is ByteString)
+            {
+                // Nothing in Base64 needs escaping
+                builder.Append('"');
+                builder.Append(((ByteString) value).ToBase64());
+                builder.Append('"');
+            }
+            else if (value is string)
+            {
+                WriteString(builder, (string) value);
+            }
+            else if (value is IDictionary)
+            {
+                WriteDictionary(builder, (IDictionary) value);
+            }
+            else if (value is IList)
+            {
+                WriteList(builder, (IList) value);
+            }
+            else if (value is int || value is uint)
+            {
+                IFormattable formattable = (IFormattable) value;
+                builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
+            }
+            else if (value is long || value is ulong)
+            {
+                builder.Append('"');
+                IFormattable formattable = (IFormattable) value;
+                builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
+                builder.Append('"');
+            }
+            else if (value is System.Enum)
+            {
+                if (System.Enum.IsDefined(value.GetType(), value))
+                {
+                    WriteString(builder, value.ToString());
+                }
+                else
+                {
+                    WriteValue(builder, (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")
+                {
+                    builder.Append('"');
+                    builder.Append(text);
+                    builder.Append('"');
+                }
+                else
+                {
+                    builder.Append(text);
+                }
+            }
+            else if (value is IMessage)
+            {
+                IMessage message = (IMessage) value;
+                if (message.Descriptor.IsWellKnownType)
+                {
+                    WriteWellKnownTypeValue(builder, message.Descriptor, value);
+                }
+                else
+                {
+                    WriteMessage(builder, (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(StringBuilder builder, 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(builder);
+                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(builder, value);
+                return;
+            }
+            if (descriptor.FullName == Timestamp.Descriptor.FullName)
+            {
+                WriteTimestamp(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == Duration.Descriptor.FullName)
+            {
+                WriteDuration(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == FieldMask.Descriptor.FullName)
+            {
+                WriteFieldMask(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == Struct.Descriptor.FullName)
+            {
+                WriteStruct(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == ListValue.Descriptor.FullName)
+            {
+                var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
+                WriteList(builder, (IList) fieldAccessor.GetValue((IMessage) value));
+                return;
+            }
+            if (descriptor.FullName == Value.Descriptor.FullName)
+            {
+                WriteStructFieldValue(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == Any.Descriptor.FullName)
+            {
+                WriteAny(builder, (IMessage) value);
+                return;
+            }
+            WriteMessage(builder, (IMessage) value);
+        }
+
+        private void WriteTimestamp(StringBuilder builder, 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);
+            builder.Append(Timestamp.ToJson(seconds, nanos, DiagnosticOnly));
+        }
+
+        private void WriteDuration(StringBuilder builder, 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);
+            builder.Append(Duration.ToJson(seconds, nanos, DiagnosticOnly));
+        }
+
+        private void WriteFieldMask(StringBuilder builder, IMessage value)
+        {
+            var paths = (IList<string>) value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value);
+            builder.Append(FieldMask.ToJson(paths, DiagnosticOnly));
+        }
+
+        private void WriteAny(StringBuilder builder, IMessage value)
+        {
+            if (DiagnosticOnly)
+            {
+                WriteDiagnosticOnlyAny(builder, value);
+                return;
+            }
+
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            string typeName = GetTypeName(typeUrl);
+            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);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+
+            if (descriptor.IsWellKnownType)
+            {
+                builder.Append(PropertySeparator);
+                WriteString(builder, AnyWellKnownTypeValueField);
+                builder.Append(NameValueSeparator);
+                WriteWellKnownTypeValue(builder, descriptor, message);
+            }
+            else
+            {
+                WriteMessageFields(builder, message, true);
+            }
+            builder.Append(" }");
+        }
+
+        private void WriteDiagnosticOnlyAny(StringBuilder builder, IMessage value)
+        {
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+            builder.Append(PropertySeparator);
+            WriteString(builder, AnyDiagnosticValueField);
+            builder.Append(NameValueSeparator);
+            builder.Append('"');
+            builder.Append(data.ToBase64());
+            builder.Append('"');
+            builder.Append(" }");
+        }
+
+        internal static string GetTypeName(String typeUrl)
+        {
+            string[] parts = typeUrl.Split('/');
+            if (parts.Length != 2 || parts[0] != TypeUrlPrefix)
+            {
+                throw new InvalidProtocolBufferException($"Invalid type url: {typeUrl}");
+            }
+            return parts[1];
+        }
+
+        private void WriteStruct(StringBuilder builder, IMessage message)
+        {
+            builder.Append("{ ");
+            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)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                WriteString(builder, key);
+                builder.Append(NameValueSeparator);
+                WriteStructFieldValue(builder, value);
+                first = false;
+            }
+            builder.Append(first ? "}" : " }");
+        }
+
+        private void WriteStructFieldValue(StringBuilder builder, 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(builder, 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(builder, nestedMessage.Descriptor, nestedMessage);
+                    return;
+                case Value.NullValueFieldNumber:
+                    WriteNull(builder);
+                    return;
+                default:
+                    throw new InvalidOperationException("Unexpected case in struct field: " + specifiedField.FieldNumber);
+            }
+        }
+
+        internal void WriteList(StringBuilder builder, IList list)
+        {
+            builder.Append("[ ");
+            bool first = true;
+            foreach (var value in list)
+            {
+                if (!first)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                WriteValue(builder, value);
+                first = false;
+            }
+            builder.Append(first ? "]" : " ]");
+        }
+
+        internal void WriteDictionary(StringBuilder builder, IDictionary dictionary)
+        {
+            builder.Append("{ ");
+            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)
+                {
+                    builder.Append(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(builder, keyText);
+                builder.Append(NameValueSeparator);
+                WriteValue(builder, pair.Value);
+                first = false;
+            }
+            builder.Append(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(StringBuilder builder, string text)
+        {
+            builder.Append('"');
+            for (int i = 0; i < text.Length; i++)
+            {
+                char c = text[i];
+                if (c < 0xa0)
+                {
+                    builder.Append(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(builder, c);
+                    HexEncodeUtf16CodeUnit(builder, 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(builder, 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(builder, c);
+                        }
+                        else
+                        {
+                            // No handling of surrogates here - that's done earlier
+                            builder.Append(c);
+                        }
+                        break;
+                }
+            }
+            builder.Append('"');
+        }
+
+        private const string Hex = "0123456789abcdef";
+        private static void HexEncodeUtf16CodeUnit(StringBuilder builder, char c)
+        {
+            builder.Append("\\u");
+            builder.Append(Hex[(c >> 12) & 0xf]);
+            builder.Append(Hex[(c >> 8) & 0xf]);
+            builder.Append(Hex[(c >> 4) & 0xf]);
+            builder.Append(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));
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs
new file mode 100644
index 0000000..80d3013
--- /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 = JsonFormatter.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..225ac0d
--- /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-alpha4")]

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..7de7b5f
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
@@ -0,0 +1,5454 @@
+// 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",
+            "ZSKuBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwKFGph",
+            "dmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVfZmls",
+            "ZXMYCiABKAg6BWZhbHNlEiwKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2FuZF9o",
+            "YXNoGBQgASgIOgVmYWxzZRIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
+            "ASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUucHJv",
+            "dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
+            "YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
+            "bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
+            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs",
+            "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz",
+            "cGFjZRglIAEoCRIrCh9qYXZhbmFub191c2VfZGVwcmVjYXRlZF9wYWNrYWdl",
+            "GCYgASgIQgIYARJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRpbWl6",
+            "ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JVTlRJ",
+            "TUUQAyoJCOgHEICAgIACIuYBCg5NZXNzYWdlT3B0aW9ucxImChdtZXNzYWdl",
+            "X3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3RhbmRhcmRf",
+            "ZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVuaW50ZXJw",
+            "cmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVy",
+            "cHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0aW9ucxI6CgVj",
+            "dHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuQ1R5",
+            "cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYgASgOMiQu",
+            "Z29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpTX05PUk1B",
+            "TBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVm",
+            "YWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w",
+            "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w",
+            "dGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5H",
+            "X1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklO",
+            "RxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIijQEKC0VudW1PcHRpb25z",
+            "EhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZh",
+            "bHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5w",
+            "cm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIifQoQRW51",
+            "bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1",
+            "bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu",
+            "VW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZpY2VPcHRp",
+            "b25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0",
+            "ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJl",
+            "dGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9kT3B0aW9ucxIZCgpkZXBy",
+            "ZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjn",
+            "ByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJ",
+            "COgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiAD",
+            "KAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1l",
+            "UGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2lu",
+            "dF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoM",
+            "ZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9h",
+            "Z2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0",
+            "GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNlQ29kZUlu",
+            "Zm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNl",
+            "Q29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgYASADKAVC",
+            "AhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVudHMYAyAB",
+            "KAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGluZ19kZXRh",
+            "Y2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUluZm8SQQoK",
+            "YW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRD",
+            "b2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0aBgBIAMo",
+            "BUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyABKAUSCwoD",
+            "ZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2NyaXB0b3JQ",
+            "cm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5S",
+            "ZWZsZWN0aW9u"));
+      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", "JavananoUseDeprecatedPackage", "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_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL;
+    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_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE;
+    /// <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 != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) hash ^= Label.GetHashCode();
+      if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) 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 != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
+        output.WriteRawTag(32);
+        output.WriteEnum((int) Label);
+      }
+      if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
+        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 != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Label);
+      }
+      if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
+        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 != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
+        Label = other.Label;
+      }
+      if (other.Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
+        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>
+        TYPE_DOUBLE = 1,
+        TYPE_FLOAT = 2,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+        ///  negative values are likely.
+        /// </summary>
+        TYPE_INT64 = 3,
+        TYPE_UINT64 = 4,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+        ///  negative values are likely.
+        /// </summary>
+        TYPE_INT32 = 5,
+        TYPE_FIXED64 = 6,
+        TYPE_FIXED32 = 7,
+        TYPE_BOOL = 8,
+        TYPE_STRING = 9,
+        /// <summary>
+        ///  Tag-delimited aggregate.
+        /// </summary>
+        TYPE_GROUP = 10,
+        /// <summary>
+        ///  Length-delimited aggregate.
+        /// </summary>
+        TYPE_MESSAGE = 11,
+        /// <summary>
+        ///  New in version 2.
+        /// </summary>
+        TYPE_BYTES = 12,
+        TYPE_UINT32 = 13,
+        TYPE_ENUM = 14,
+        TYPE_SFIXED32 = 15,
+        TYPE_SFIXED64 = 16,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
+        TYPE_SINT32 = 17,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
+        TYPE_SINT64 = 18,
+      }
+
+      internal enum Label {
+        /// <summary>
+        ///  0 is reserved for errors
+        /// </summary>
+        LABEL_OPTIONAL = 1,
+        LABEL_REQUIRED = 2,
+        /// <summary>
+        ///  TODO(sanjay): Should we add LABEL_MAP?
+        /// </summary>
+        LABEL_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_;
+      javananoUseDeprecatedPackage_ = other.javananoUseDeprecatedPackage_;
+      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_ = global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED;
+    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 "javanano_use_deprecated_package" field.</summary>
+    public const int JavananoUseDeprecatedPackageFieldNumber = 38;
+    private bool javananoUseDeprecatedPackage_;
+    /// <summary>
+    ///  Whether the nano proto compiler should generate in the deprecated non-nano
+    ///  suffixed package.
+    /// </summary>
+    [global::System.ObsoleteAttribute()]
+    public bool JavananoUseDeprecatedPackage {
+      get { return javananoUseDeprecatedPackage_; }
+      set {
+        javananoUseDeprecatedPackage_ = 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 (JavananoUseDeprecatedPackage != other.JavananoUseDeprecatedPackage) 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 != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) 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();
+      if (JavananoUseDeprecatedPackage != false) hash ^= JavananoUseDeprecatedPackage.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 != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) {
+        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);
+      }
+      if (JavananoUseDeprecatedPackage != false) {
+        output.WriteRawTag(176, 2);
+        output.WriteBool(JavananoUseDeprecatedPackage);
+      }
+      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 != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) {
+        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);
+      }
+      if (JavananoUseDeprecatedPackage != false) {
+        size += 2 + 1;
+      }
+      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 != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) {
+        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;
+      }
+      if (other.JavananoUseDeprecatedPackage != false) {
+        JavananoUseDeprecatedPackage = other.JavananoUseDeprecatedPackage;
+      }
+      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 304: {
+            JavananoUseDeprecatedPackage = input.ReadBool();
+            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>
+        SPEED = 1,
+        /// <summary>
+        ///  etc.
+        /// </summary>
+        CODE_SIZE = 2,
+        /// <summary>
+        ///  Generate code using MessageLite and the lite runtime.
+        /// </summary>
+        LITE_RUNTIME = 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_ = global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING;
+    /// <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_ = global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL;
+    /// <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 != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) hash ^= Ctype.GetHashCode();
+      if (Packed != false) hash ^= Packed.GetHashCode();
+      if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) 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 != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) {
+        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 != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) {
+        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 != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Ctype);
+      }
+      if (Packed != false) {
+        size += 1 + 1;
+      }
+      if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) {
+        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 != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) {
+        Ctype = other.Ctype;
+      }
+      if (other.Packed != false) {
+        Packed = other.Packed;
+      }
+      if (other.Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) {
+        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>
+        STRING = 0,
+        CORD = 1,
+        STRING_PIECE = 2,
+      }
+
+      internal enum JSType {
+        /// <summary>
+        ///  Use the default type.
+        /// </summary>
+        JS_NORMAL = 0,
+        /// <summary>
+        ///  Use JavaScript strings.
+        /// </summary>
+        JS_STRING = 1,
+        /// <summary>
+        ///  Use JavaScript numbers.
+        /// </summary>
+        JS_NUMBER = 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..c6caaec
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -0,0 +1,359 @@
+#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.Linq;
+using Google.Protobuf.Compatibility;
+
+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 readonly FieldDescriptorProto proto;
+        private EnumDescriptor enumType;
+        private MessageDescriptor messageType;
+        private readonly MessageDescriptor containingType;
+        private readonly OneofDescriptor containingOneof;
+        private FieldType fieldType;
+        private readonly string propertyName; // Annoyingly, needed in Crosslink.
+        private IFieldAccessor accessor;
+
+        internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
+                                 MessageDescriptor parent, int index, string propertyName)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            this.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;
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal FieldDescriptorProto Proto { get { return proto; } }
+
+        /// <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 { get { return 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.TYPE_DOUBLE:
+                    return FieldType.Double;
+                case FieldDescriptorProto.Types.Type.TYPE_FLOAT:
+                    return FieldType.Float;
+                case FieldDescriptorProto.Types.Type.TYPE_INT64:
+                    return FieldType.Int64;
+                case FieldDescriptorProto.Types.Type.TYPE_UINT64:
+                    return FieldType.UInt64;
+                case FieldDescriptorProto.Types.Type.TYPE_INT32:
+                    return FieldType.Int32;
+                case FieldDescriptorProto.Types.Type.TYPE_FIXED64:
+                    return FieldType.Fixed64;
+                case FieldDescriptorProto.Types.Type.TYPE_FIXED32:
+                    return FieldType.Fixed32;
+                case FieldDescriptorProto.Types.Type.TYPE_BOOL:
+                    return FieldType.Bool;
+                case FieldDescriptorProto.Types.Type.TYPE_STRING:
+                    return FieldType.String;
+                case FieldDescriptorProto.Types.Type.TYPE_GROUP:
+                    return FieldType.Group;
+                case FieldDescriptorProto.Types.Type.TYPE_MESSAGE:
+                    return FieldType.Message;
+                case FieldDescriptorProto.Types.Type.TYPE_BYTES:
+                    return FieldType.Bytes;
+                case FieldDescriptorProto.Types.Type.TYPE_UINT32:
+                    return FieldType.UInt32;
+                case FieldDescriptorProto.Types.Type.TYPE_ENUM:
+                    return FieldType.Enum;
+                case FieldDescriptorProto.Types.Type.TYPE_SFIXED32:
+                    return FieldType.SFixed32;
+                case FieldDescriptorProto.Types.Type.TYPE_SFIXED64:
+                    return FieldType.SFixed64;
+                case FieldDescriptorProto.Types.Type.TYPE_SINT32:
+                    return FieldType.SInt32;
+                case FieldDescriptorProto.Types.Type.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
+        {
+            get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsMap
+        {
+            get { return 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.
+            get { return Proto.Options == null || Proto.Options.Packed; }
+        }        
+
+        /// <summary>
+        /// Get the field's containing message type.
+        /// </summary>
+        public MessageDescriptor ContainingType
+        {
+            get { return containingType; }
+        }
+
+        /// <summary>
+        /// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
+        /// </summary>
+        public OneofDescriptor ContainingOneof
+        {
+            get { return containingOneof; }
+        }
+
+        /// <summary>
+        /// Returns the type of the field.
+        /// </summary>
+        public FieldType FieldType
+        {
+            get { return fieldType; }
+        }
+
+        /// <summary>
+        /// Returns the field number declared in the proto file.
+        /// </summary>
+        public int FieldNumber
+        {
+            get { return 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(propertyName);
+        }
+
+        private IFieldAccessor CreateAccessor(string propertyName)
+        {
+            // 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..f5798d1
--- /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[JsonFormatter.ToCamelCase(field.Name)] = field;
+                map[field.Name] = 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/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..48cd99a
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
@@ -0,0 +1,230 @@
+// 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",
+            "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQksKE2Nv",
+            "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAGgAQGiAgNHUEKqAh5Hb29n",
+            "bGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
+      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 message along with a URL
+  ///  that describes the type of the serialized message.
+  ///
+  ///  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 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`).
+    ///  * 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 valid serialized data 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..9d43856
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
@@ -0,0 +1,79 @@
+#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
+    {
+        // 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)
+        {
+            return "type.googleapis.com/" + descriptor.FullName;
+        }
+
+        /// <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();
+            string targetTypeUrl = GetTypeUrl(target.Descriptor);
+            if (TypeUrl != targetTypeUrl)
+            {
+                throw new InvalidProtocolBufferException(string.Format("Type url for {0} is {1}; Any message's type url is {2}",
+                    target.Descriptor.Name, targetTypeUrl, TypeUrl));
+            }
+            target.MergeFrom(Value);
+            return target;
+        }
+
+        /// <summary>
+        /// Packs the specified message into an Any message.
+        /// </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)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            return new Any { TypeUrl = GetTypeUrl(message.Descriptor), 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..de7aea3
--- /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_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) 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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) 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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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..73e221d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
@@ -0,0 +1,229 @@
+// 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",
+            "ASgFQlAKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAaAB",
+            "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
+            "dG8z"));
+      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..6cad412
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
@@ -0,0 +1,131 @@
+// 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",
+            "ZiIHCgVFbXB0eUJQChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
+            "UAGgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw",
+            "ZXNiBnByb3RvMw=="));
+      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..2ba2b96
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
@@ -0,0 +1,265 @@
+// 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 applies 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"
+  ///      }
+  /// </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..df1292d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
@@ -0,0 +1,122 @@
+#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.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 builder = new StringBuilder();
+                JsonFormatter.WriteString(builder, string.Join(",", paths.Select(JsonFormatter.ToCamelCase)));
+                return builder.ToString();
+            }
+            else
+            {
+                if (diagnosticOnly)
+                {
+                    var builder = new StringBuilder();
+                    builder.Append("{ \"@warning\": \"Invalid FieldMask\", \"paths\": ");
+                    JsonFormatter.Default.WriteList(builder, (IList) paths);
+                    builder.Append(" }");
+                    return builder.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..8e2ce8c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
@@ -0,0 +1,599 @@
+// 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",
+            "QUxVRRAAQk4KE2NvbS5nb29nbGUucHJvdG9idWZCC1N0cnVjdFByb3RvUAGg",
+            "AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy",
+            "b3RvMw=="));
+      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>
+    NULL_VALUE = 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>
+    ///  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_ : global::Google.Protobuf.WellKnownTypes.NullValue.NULL_VALUE; }
+      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..318b0f6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -0,0 +1,240 @@
+// 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",
+            "AiABKAVCVAoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
+            "AaABAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBl",
+            "c2IGcHJvdG8z"));
+      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..8faa1d1
--- /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>
+    SYNTAX_PROTO2 = 0,
+    /// <summary>
+    ///  Syntax `proto3`.
+    /// </summary>
+    SYNTAX_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_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) 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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN;
+    /// <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_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN;
+    /// <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 != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) hash ^= Kind.GetHashCode();
+      if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) 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 != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) Kind);
+      }
+      if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) {
+        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 != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Kind);
+      }
+      if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) {
+        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 != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) {
+        Kind = other.Kind;
+      }
+      if (other.Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) {
+        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>
+        TYPE_UNKNOWN = 0,
+        /// <summary>
+        ///  Field type double.
+        /// </summary>
+        TYPE_DOUBLE = 1,
+        /// <summary>
+        ///  Field type float.
+        /// </summary>
+        TYPE_FLOAT = 2,
+        /// <summary>
+        ///  Field type int64.
+        /// </summary>
+        TYPE_INT64 = 3,
+        /// <summary>
+        ///  Field type uint64.
+        /// </summary>
+        TYPE_UINT64 = 4,
+        /// <summary>
+        ///  Field type int32.
+        /// </summary>
+        TYPE_INT32 = 5,
+        /// <summary>
+        ///  Field type fixed64.
+        /// </summary>
+        TYPE_FIXED64 = 6,
+        /// <summary>
+        ///  Field type fixed32.
+        /// </summary>
+        TYPE_FIXED32 = 7,
+        /// <summary>
+        ///  Field type bool.
+        /// </summary>
+        TYPE_BOOL = 8,
+        /// <summary>
+        ///  Field type string.
+        /// </summary>
+        TYPE_STRING = 9,
+        /// <summary>
+        ///  Field type group. Proto2 syntax only, and deprecated.
+        /// </summary>
+        TYPE_GROUP = 10,
+        /// <summary>
+        ///  Field type message.
+        /// </summary>
+        TYPE_MESSAGE = 11,
+        /// <summary>
+        ///  Field type bytes.
+        /// </summary>
+        TYPE_BYTES = 12,
+        /// <summary>
+        ///  Field type uint32.
+        /// </summary>
+        TYPE_UINT32 = 13,
+        /// <summary>
+        ///  Field type enum.
+        /// </summary>
+        TYPE_ENUM = 14,
+        /// <summary>
+        ///  Field type sfixed32.
+        /// </summary>
+        TYPE_SFIXED32 = 15,
+        /// <summary>
+        ///  Field type sfixed64.
+        /// </summary>
+        TYPE_SFIXED64 = 16,
+        /// <summary>
+        ///  Field type sint32.
+        /// </summary>
+        TYPE_SINT32 = 17,
+        /// <summary>
+        ///  Field type sint64.
+        /// </summary>
+        TYPE_SINT64 = 18,
+      }
+
+      /// <summary>
+      ///  Whether a field is optional, required, or repeated.
+      /// </summary>
+      public enum Cardinality {
+        /// <summary>
+        ///  For fields with unknown cardinality.
+        /// </summary>
+        CARDINALITY_UNKNOWN = 0,
+        /// <summary>
+        ///  For optional fields.
+        /// </summary>
+        CARDINALITY_OPTIONAL = 1,
+        /// <summary>
+        ///  For required fields. Proto2 syntax only.
+        /// </summary>
+        CARDINALITY_REQUIRED = 2,
+        /// <summary>
+        ///  For repeated fields.
+        /// </summary>
+        CARDINALITY_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_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) 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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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 != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        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..d6796d1
--- /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",
+            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJT",
+            "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQH4AQGi",
+            "AgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3Rv",
+            "Mw=="));
+      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/editors/proto.vim b/editors/proto.vim
index 23085a2..7f1aeb7 100644
--- a/editors/proto.vim
+++ b/editors/proto.vim
@@ -57,7 +57,7 @@
 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 b25a3c6..44006b2 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -10,6 +10,8 @@
 #   to make when building protoc.  This is particularly useful for passing
 #   -j4 to run 4 jobs simultaneously.
 
+set -e
+
 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
@@ -27,39 +29,70 @@
 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
-  cp google/protobuf/descriptor.pb.h google/protobuf/descriptor.pb.h.tmp
-  cp google/protobuf/descriptor.pb.cc google/protobuf/descriptor.pb.cc.tmp
-  cp google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp
-  cp google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp
 
   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
+    ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
+    ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto
 
-  diff google/protobuf/descriptor.pb.h google/protobuf/descriptor.pb.h.tmp > /dev/null
+  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/descriptor.pb.cc google/protobuf/descriptor.pb.cc.tmp > /dev/null
-  if test $? -ne 0; then
-    CORE_PROTO_IS_CORRECT=0
-  fi
-  diff google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp > /dev/null
-  if test $? -ne 0; then
-    CORE_PROTO_IS_CORRECT=0
-  fi
-  diff google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp > /dev/null
+  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
 
-  rm google/protobuf/descriptor.pb.h.tmp
-  rm google/protobuf/descriptor.pb.cc.tmp
-  rm google/protobuf/compiler/plugin.pb.h.tmp
-  rm google/protobuf/compiler/plugin.pb.cc.tmp
+  # 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_descriptors_proto.sh; then
+  echo "Generating messages for objc."
+  objectivec/generate_descriptors_proto.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 57e26a9..0000000
--- a/java/README.txt
+++ /dev/null
@@ -1,96 +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.
-
-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..74d5ead
--- /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-2</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..9f418f2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -0,0 +1,533 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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, getAllFields(), output, false);
+  }
+
+  protected int memoizedSize = -1;
+
+  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>
+      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 Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
+        int index) {
+      throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() 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/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..1238498
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -0,0 +1,363 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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.");
+    }
+  }
+
+  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 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 {@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/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/AbstractParser.java
rename to java/core/src/main/java/com/google/protobuf/AbstractParser.java
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..bb6446b
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.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;
+
+import com.google.protobuf.Internal.ProtobufList;
+
+import java.util.AbstractList;
+import java.util.Collection;
+
+/**
+ * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
+ * methods are check if the list is mutable before proceeding. Subclasses must invoke
+ * {@link #ensureIsMutable()} manually when overriding those methods.
+ */
+abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
+
+  /**
+   * Whether or not this list is modifiable.
+   */
+  private boolean isMutable;
+  
+  /**
+   * Constructs a mutable list by default.
+   */
+  AbstractProtobufList() {
+    isMutable = true;
+  }
+
+  @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..70e042f
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -0,0 +1,251 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.List;
+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 int DEFAULT_CAPACITY = 10;
+  
+  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(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList} with the provided capacity.
+   */
+  BooleanArrayList(int capacity) {
+    array = new boolean[capacity];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList} containing the same elements as
+   * {@code other}.
+   */
+  BooleanArrayList(List<Boolean> other) {
+    if (other instanceof BooleanArrayList) {
+      BooleanArrayList list = (BooleanArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new boolean[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @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/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
new file mode 100644
index 0000000..305236f
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -0,0 +1,1456 @@
+// Copyright 2007 Google Inc.  All rights reserved.
+
+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.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);
+
+  /**
+   * 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 ArrayIndexOutOfBoundsException {@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 (ArrayIndexOutOfBoundsException 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) {
+    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);
+  }
+  
+  /**
+   * 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 the complete contents of this byte string to
+   * the specified output stream argument.
+   *
+   * <p>It is assumed that the {@link OutputStream} will not modify the contents passed it
+   * it. It may be possible for a malicious {@link OutputStream} to corrupt
+   * the data underlying the {@link ByteString}.
+   *
+   * @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;
+
+  /**
+   * 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 ArrayIndexOutOfBoundsException 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 ArrayIndexOutOfBoundsException 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
+    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..b3118ee
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -0,0 +1,1282 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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) {
+    return newInstance(buf, off, len, false);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array slice.
+   */
+  public static CodedInputStream newInstance(final byte[] buf, final int off,
+                                             final int len, 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 {
+      // 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;
+    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, 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) {
+    buffer = new byte[BUFFER_SIZE];
+    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..d8ebad2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -0,0 +1,1332 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.Utf8.UnpairedSurrogateException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+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.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class CodedOutputStream {
+
+  private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
+
+  // TODO(dweis): Consider migrating to a ByteBuffer.
+  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 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. */
+  // TODO(dweis): Document behavior on ill-formed UTF-16 input.
+  public void writeStringNoTag(final String value) throws IOException {
+    try {
+      efficientWriteStringNoTag(value);
+    } catch (UnpairedSurrogateException e) {
+      logger.log(Level.WARNING,
+          "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", e);
+      inefficientWriteStringNoTag(value);
+    }
+  }
+
+  /** Write a {@code string} field to the stream. */
+  private void inefficientWriteStringNoTag(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.
+    // TODO(dweis): Consider using nio Charset methods instead.
+    final byte[] bytes = value.getBytes(Internal.UTF_8);
+    writeRawVarint32(bytes.length);
+    writeRawBytes(bytes);
+  }
+
+  /**
+   * Write a {@code string} field to the stream efficiently. If the {@code string} is malformed,
+   * this method rolls back its changes and throws an {@link UnpairedSurrogateException} with the
+   * intent that the caller will catch and retry with {@link #inefficientWriteStringNoTag(String)}.
+   *
+   * @param value the string to write to the stream
+   *
+   * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16.
+   */
+  private void efficientWriteStringNoTag(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. We take advantage of this in both branches below.
+    final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+    final int maxLengthVarIntSize = computeRawVarint32Size(maxLength);
+
+    // If we are streaming and the potential length is too big to fit in our buffer, we take the
+    // slower path. Otherwise, we're good to try the fast path.
+    if (output != null && maxLengthVarIntSize + maxLength > limit - position) {
+      // 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);
+      writeRawVarint32(actualLength);
+      writeRawBytes(encodedBytes, 0, actualLength);
+    } else {
+      // 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 = computeRawVarint32Size(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;
+          writeRawVarint32(length);
+          position = newPosition;
+        } else {
+          length = Utf8.encodedLength(value);
+          writeRawVarint32(length);
+          position = Utf8.encode(value, buffer, position, limit - position);
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Be extra careful and restore the original position for retrying the write with the less
+        // efficient path.
+        position = oldPosition;
+        throw e;
+      } catch (ArrayIndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+      totalBytesWritten += length;
+    }
+  }
+
+  /** Write a {@code group} field to the stream. */
+  public void writeGroupNoTag(final MessageLite value) throws IOException {
+    value.writeTo(this);
+  }
+
+
+  /** 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 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) {
+    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 computeRawVarint32Size(length) + length;
+  }
+
+  /**
+   * 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 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;
+
+    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 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 & (~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;
+  }
+
+  /** 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(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;
+  }
+
+  /** 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/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..5e15cfb
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -0,0 +1,2439 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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. */
+    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));
+    }
+
+    /** 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.
+     */
+    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;
+      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. */
+    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;
+    }
+
+    /** 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. */
+    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 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. */
+    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() {
+      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? */
+    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?
+     */
+    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. */
+    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();
+    }
+
+    @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.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 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.
+     */
+    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));
+    }
+
+    /**
+     * 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. */
+    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);
+    }
+
+    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. */
+    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; }
+
+    /** 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..bcc9d6e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -0,0 +1,250 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.List;
+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 int DEFAULT_CAPACITY = 10;
+  
+  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(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList} with the provided capacity.
+   */
+  DoubleArrayList(int capacity) {
+    array = new double[capacity];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
+   */
+  DoubleArrayList(List<Double> other) {
+    if (other instanceof DoubleArrayList) {
+      DoubleArrayList list = (DoubleArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new double[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @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/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/DynamicMessage.java
rename to java/core/src/main/java/com/google/protobuf/DynamicMessage.java
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..6f41fb8
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
@@ -0,0 +1,36 @@
+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/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/Extension.java
rename to java/core/src/main/java/com/google/protobuf/Extension.java
diff --git a/java/src/main/java/com/google/protobuf/ExtensionLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ExtensionLite.java
rename to java/core/src/main/java/com/google/protobuf/ExtensionLite.java
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/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/FieldSet.java
rename to java/core/src/main/java/com/google/protobuf/FieldSet.java
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..033b5ee
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -0,0 +1,249 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.List;
+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 int DEFAULT_CAPACITY = 10;
+  
+  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(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList} with the provided capacity.
+   */
+  FloatArrayList(int capacity) {
+    array = new float[capacity];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
+   */
+  FloatArrayList(List<Float> other) {
+    if (other instanceof FloatArrayList) {
+      FloatArrayList list = (FloatArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new float[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @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..ceb97a4
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -0,0 +1,2830 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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();
+  }
+
+  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 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 (Java 1.6 override semantics, but we must support 1.5)
+  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 (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);
+  }
+
+  /**
+   * 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 (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);
+  }
+
+  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>
+      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.
+     */
+    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;
+      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;
+    }
+
+    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 Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
+        int index) {
+      return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
+          this, index);
+    }
+
+    //@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 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 (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;
+      }
+    }
+
+    /**
+     * 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.
+    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 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 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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    @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 (Java 1.6 override semantics, but we must support 1.5)
+    @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.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 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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (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);
+      }
+    }
+  }
+
+  /**
+   * 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();
+      }
+
+      public Object get(final GeneratedMessage message) {
+        return invokeOrDie(getMethod, message);
+      }
+      public Object get(GeneratedMessage.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      public Object getRaw(final GeneratedMessage message) {
+        return get(message);
+      }
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(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 getRepeatedRaw(final GeneratedMessage message,
+                                final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      public Object getRepeated(GeneratedMessage.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
+          int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() 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.");
+      }
+      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);
+      }
+
+      public Object get(final GeneratedMessage message) {
+        return invokeOrDie(getMethod, message);
+      }
+      public Object get(GeneratedMessage.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      public Object getRaw(final GeneratedMessage message) {
+        return get(message);
+      }
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(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 Object getRepeatedRaw(GeneratedMessage message, int index) {
+        return getRepeated(message, index);
+      }
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
+          int index) {
+        return getRepeated(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.");
+      }
+      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());
+      }
+
+      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);
+      }
+
+      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);
+      }
+
+      public Object getRaw(GeneratedMessage message) {
+        return get(message);
+      }
+
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
+
+      public void set(Builder builder, Object value) {
+        clear(builder);
+        for (Object entry : (List) value) {
+          addRepeated(builder, entry);
+        }
+      }
+
+      public Object getRepeated(GeneratedMessage message, int index) {
+        return getMapField(message).getList().get(index);
+      }
+
+      public Object getRepeated(Builder builder, int index) {
+        return getMapField(builder).getList().get(index);
+      }
+
+      public Object getRepeatedRaw(GeneratedMessage message, int index) {
+        return getRepeated(message, index);
+      }
+
+      public Object getRepeatedRaw(Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+
+      public void setRepeated(Builder builder, int index, Object value) {
+        getMutableMapField(builder).getMutableList().set(index, (Message) value);
+      }
+
+      public void addRepeated(Builder builder, Object value) {
+        getMutableMapField(builder).getMutableList().add((Message) value);
+      }
+
+      public boolean has(GeneratedMessage message) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      public boolean has(Builder builder) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      public int getRepeatedCount(GeneratedMessage message) {
+        return getMapField(message).getList().size();
+      }
+
+      public int getRepeatedCount(Builder builder) {
+        return getMapField(builder).getList().size();
+      }
+
+      public void clear(Builder builder) {
+        getMutableMapField(builder).getMutableList().clear();
+      }
+
+      public com.google.protobuf.Message.Builder newBuilder() {
+        return mapEntryMessageDefaultInstance.newBuilderForType();
+      }
+
+      public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+
+      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..81e1862
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -0,0 +1,1276 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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.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
+        implements Serializable {
+
+  private static final long serialVersionUID = 1L;
+
+  /** For use by generated code only. Lazily initialized to reduce allocations. */
+  protected UnknownFieldSetLite unknownFields = null;
+  
+  /** For use by generated code only.  */
+  protected int memoizedSerializedSize = -1;
+  
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final Parser<MessageType> getParserForType() {
+    return (Parser<MessageType>) dynamicMethod(MethodToInvoke.GET_PARSER);
+  }
+
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final MessageType getDefaultInstanceForType() {
+    return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE);
+  }
+
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final BuilderType newBuilderForType() {
+    return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
+  }
+
+  // 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 == null) {
+      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 doneParsing() {
+    if (unknownFields == null) {
+      unknownFields = UnknownFieldSetLite.getDefaultInstance();
+    } else {
+      unknownFields.makeImmutable();
+    }
+  }
+
+  public final boolean isInitialized() {
+    return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
+  }
+
+  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 {
+    IS_INITIALIZED,
+    PARSE_PARTIAL_FROM,
+    MERGE_FROM,
+    MAKE_IMMUTABLE,
+    NEW_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 PARSE_PARTIAL_FROM} 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
+   * <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 MERGE_FROM} is parameterized with a {@code MessageType} and merges the fields from
+   * that instance into this 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);
+  }
+
+  /**
+   * 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<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_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_INSTANCE);
+        newInstance.dynamicMethod(MethodToInvoke.MERGE_FROM, instance);
+        instance = newInstance;
+        isBuilt = false;
+      }
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public final boolean isInitialized() {
+      return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */);
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public final BuilderType clear() {
+      // No need to copy on write since we're dropping the instance anyways.
+      instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+      return (BuilderType) this;
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public BuilderType clone() {
+      BuilderType builder =
+          (BuilderType) getDefaultInstanceForType().newBuilderForType();
+      builder.mergeFrom(buildPartial());
+      return builder;
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public MessageType buildPartial() {
+      if (isBuilt) {
+        return instance;
+      }
+      
+      instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+      instance.unknownFields.makeImmutable();
+      
+      isBuilt = true;
+      return instance;
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public final MessageType build() {
+      MessageType result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+    
+    /** All subclasses implement this. */
+    public BuilderType mergeFrom(MessageType message) {
+      copyOnWrite();
+      instance.dynamicMethod(MethodToInvoke.MERGE_FROM, message);
+      return (BuilderType) this;
+    }
+    
+    public MessageType getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+    
+    public BuilderType mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      MessageType parsedMessage = null;
+      try {
+        parsedMessage =
+            (MessageType) getDefaultInstanceForType().getParserForType().parsePartialFrom(
+                input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (MessageType) e.getUnfinishedMessage();
+        throw e;
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      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);
+    }
+    
+    /**
+     * 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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    @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 (Java 1.6 override semantics, but we must support 1.5)
+    @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 doneParsing() {
+      super.doneParsing();
+      
+      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 (Java 1.6 override semantics, but we must support 1.5)
+    protected void copyOnWrite() {
+      if (!isBuilt) {
+        return;
+      }
+      
+      super.copyOnWrite();
+      instance.extensions = instance.extensions.clone();
+    }
+
+    // @Override (Java 1.6 override semantics, but we must support 1.5)
+    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 (Java 1.6 override semantics, but we must support 1.5)
+    public final <Type> boolean hasExtension(
+        final ExtensionLite<MessageType, Type> extension) {
+      return instance.hasExtension(extension);
+    }
+
+    /** 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 ExtensionLite<MessageType, List<Type>> extension) {
+      return instance.getExtensionCount(extension);
+    }
+
+    /** 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 ExtensionLite<MessageType, Type> extension) {
+      return instance.getExtension(extension);
+    }
+
+    /** 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 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;
+
+    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>
+          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. */
+    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 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;
+      }
+    }
+
+    public FieldType getLiteType() {
+      return descriptor.getLiteType();
+    }
+
+    public boolean isRepeated() {
+      return descriptor.isRepeated;
+    }
+
+    public Type getDefaultValue() {
+      return defaultValue;
+    }
+  }
+
+  /**
+   * 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 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);
+      }
+    }
+  }
+
+  /**
+   * 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);
+  }
+  
+  /**
+   * 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);
+  }
+  
+  /**
+   * A static helper method for parsing a partial from input using the extension registry and the
+   * instance.
+   */
+  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws InvalidProtocolBufferException {
+    try {
+      return (T) instance.dynamicMethod(
+          MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry);
+    } catch (RuntimeException e) {
+      if (e.getCause() instanceof InvalidProtocolBufferException) {
+        throw (InvalidProtocolBufferException) e.getCause();
+      }
+      throw e;
+    }
+  }
+  
+  /**
+   * 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);
+    }
+  }
+  
+  protected static IntList newIntList() {
+    return new IntArrayList();
+  }
+  
+  protected static IntList newIntListWithCapacity(int capacity) {
+    return new IntArrayList(capacity);
+  }
+  
+  protected static IntList newIntList(List<Integer> toCopy) {
+    return new IntArrayList(toCopy);
+  }
+  
+  protected static IntList emptyIntList() {
+    return IntArrayList.emptyList();
+  }
+
+  protected static LongList newLongList() {
+    return new LongArrayList();
+  }
+
+  protected static LongList newLongListWithCapacity(int capacity) {
+    return new LongArrayList(capacity);
+  }
+  
+  protected static LongList newLongList(List<Long> toCopy) {
+    return new LongArrayList(toCopy);
+  }
+  
+  protected static LongList emptyLongList() {
+    return LongArrayList.emptyList();
+  }
+  
+  protected static FloatList newFloatList() {
+    return new FloatArrayList();
+  }
+  
+  protected static FloatList newFloatListWithCapacity(int capacity) {
+    return new FloatArrayList(capacity);
+  }
+  
+  protected static FloatList newFloatList(List<Float> toCopy) {
+    return new FloatArrayList(toCopy);
+  }
+  
+  protected static FloatList emptyFloatList() {
+    return FloatArrayList.emptyList();
+  }
+  
+  protected static DoubleList newDoubleList() {
+    return new DoubleArrayList();
+  }
+  
+  protected static DoubleList newDoubleListWithCapacity(int capacity) {
+    return new DoubleArrayList(capacity);
+  }
+  
+  protected static DoubleList newDoubleList(List<Double> toCopy) {
+    return new DoubleArrayList(toCopy);
+  }
+  
+  protected static DoubleList emptyDoubleList() {
+    return DoubleArrayList.emptyList();
+  }
+  
+  protected static BooleanList newBooleanList() {
+    return new BooleanArrayList();
+  }
+  
+  protected static BooleanList newBooleanListWithCapacity(int capacity) {
+    return new BooleanArrayList(capacity);
+  }
+  
+  protected static BooleanList newBooleanList(List<Boolean> toCopy) {
+    return new BooleanArrayList(toCopy);
+  }
+  
+  protected static BooleanList emptyBooleanList() {
+    return BooleanArrayList.emptyList();
+  }
+  
+  protected static <E> ProtobufList<E> newProtobufList() {
+    return new ProtobufArrayList<E>();
+  }
+  
+  protected static <E> ProtobufList<E> newProtobufList(List<E> toCopy) {
+    return new ProtobufArrayList<E>(toCopy);
+  }
+  
+  protected static <E> ProtobufList<E> newProtobufListWithCapacity(int capacity) {
+    return new ProtobufArrayList<E>(capacity);
+  }
+  
+  protected static <E> ProtobufList<E> emptyProtobufList() {
+    return ProtobufArrayList.emptyList();
+  }
+  
+  protected static LazyStringArrayList emptyLazyStringArrayList() {
+    return LazyStringArrayList.emptyList();
+  }
+}
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..f4e68ed
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -0,0 +1,249 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.List;
+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 int DEFAULT_CAPACITY = 10;
+  
+  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(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code IntArrayList} with the provided capacity.
+   */
+  IntArrayList(int capacity) {
+    array = new int[capacity];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
+   */
+  IntArrayList(List<Integer> other) {
+    if (other instanceof IntArrayList) {
+      IntArrayList list = (IntArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new int[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @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..e19b6dc
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -0,0 +1,697 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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 class Internal {
+
+  protected static final Charset UTF_8 = Charset.forName("UTF-8");
+  protected 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>() {
+        public T doForward(Integer value) {
+          T result = enumMap.findValueByNumber(value);
+          return result == null ? unrecognizedValue : result;
+        }
+        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.
+   */
+  public static interface ProtobufList<E> extends List<E> {
+
+    /**
+     * 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();
+  }
+
+  /**
+   * 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(Object)} but more efficient in that it doesn't box the element.
+     */
+    void addInt(int element);
+
+    /**
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+     */
+    int setInt(int index, int element);
+  }
+
+  /**
+   * 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(Object)} but more efficient in that it doesn't box the element.
+     */
+    void addBoolean(boolean element);
+
+    /**
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+     */
+    boolean setBoolean(int index, boolean element);
+  }
+
+  /**
+   * 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(Object)} but more efficient in that it doesn't box the element.
+     */
+    void addLong(long element);
+
+    /**
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+     */
+    long setLong(int index, long element);
+  }
+
+  /**
+   * 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(Object)} but more efficient in that it doesn't box the element.
+     */
+    void addDouble(double element);
+
+    /**
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+     */
+    double setDouble(int index, double element);
+  }
+
+  /**
+   * 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(Object)} but more efficient in that it doesn't box the element.
+     */
+    void addFloat(float element);
+
+    /**
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+     */
+    float setFloat(int index, float element);
+  }
+}
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..5e0a485
--- /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 equals()} 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 equals()} 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/core/src/main/java/com/google/protobuf/LazyFieldLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/LazyFieldLite.java
rename to java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
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..c3be3cc
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -0,0 +1,409 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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() {
+    list = new ArrayList<Object>();
+  }
+
+  public LazyStringArrayList(int intialCapacity) {
+    list = new ArrayList<Object>(intialCapacity);
+  }
+
+  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) {
+    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..ebe6202
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -0,0 +1,249 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.List;
+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 int DEFAULT_CAPACITY = 10;
+  
+  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(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code LongArrayList} with the provided capacity.
+   */
+  LongArrayList(int capacity) {
+    array = new long[capacity];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
+   */
+  LongArrayList(List<Long> other) {
+    if (other instanceof LongArrayList) {
+      LongArrayList list = (LongArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new long[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @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/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MapEntry.java
rename to java/core/src/main/java/com/google/protobuf/MapEntry.java
diff --git a/java/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MapEntryLite.java
rename to java/core/src/main/java/com/google/protobuf/MapEntryLite.java
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..b290993
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -0,0 +1,286 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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;
+    }
+    
+    public Message convertKeyAndValueToMessage(K key, V value) {
+      return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
+    }
+    
+    public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
+      MapEntry<K, V> entry = (MapEntry<K, V>) message;
+      map.put(entry.getKey(), entry.getValue());
+    }
+
+    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..9516d71
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -0,0 +1,266 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+     * * 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.)
+    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>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.)
+    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/core/src/main/java/com/google/protobuf/MessageLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageLite.java
rename to java/core/src/main/java/com/google/protobuf/MessageLite.java
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..e69de29
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
diff --git a/java/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageOrBuilder.java
rename to java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
diff --git a/java/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageReflection.java
rename to java/core/src/main/java/com/google/protobuf/MessageReflection.java
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..f71e41b
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -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.
+
+package com.google.protobuf;
+
+import java.io.FileOutputStream;
+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.InvalidMarkException;
+import java.nio.channels.Channels;
+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();
+  }
+
+  // =================================================================
+  // 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 {
+    writeToInternal(out, buffer.position(), buffer.remaining());
+  }
+
+  @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;
+    }
+
+    // Slow path
+    if (out instanceof FileOutputStream || numberToWrite >= 8192) {
+      // Use a channel to write out the ByteBuffer.
+      Channels.newChannel(out).write(slice(sourceOffset, sourceOffset + numberToWrite));
+    } else {
+      // Just copy the data to an array and write it.
+      out.write(toByteArray());
+    }
+  }
+
+  @Override
+  public ByteBuffer asReadOnlyByteBuffer() {
+    return buffer.asReadOnlyBuffer();
+  }
+
+  @Override
+  public List<ByteBuffer> asReadOnlyByteBufferList() {
+    return Collections.singletonList(asReadOnlyByteBuffer());
+  }
+
+  @Override
+  protected String toStringInternal(Charset charset) {
+    byte[] bytes;
+    int offset;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      offset = buffer.arrayOffset() + buffer.position();
+    } else {
+      bytes = toByteArray();
+      offset = 0;
+    }
+    return new String(bytes, offset, size(), charset);
+  }
+
+  @Override
+  public boolean isValidUtf8() {
+    // TODO(nathanmittler): add a ByteBuffer fork for Utf8.isValidUtf8 to avoid the copy
+    byte[] bytes;
+    int startIndex;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      startIndex = buffer.arrayOffset() + buffer.position();
+    } else {
+      bytes = toByteArray();
+      startIndex = 0;
+    }
+    return Utf8.isValidUtf8(bytes, startIndex, startIndex + size());
+  }
+
+  @Override
+  protected int partialIsValidUtf8(int state, int offset, int length) {
+    // TODO(nathanmittler): TODO add a ByteBuffer fork for Utf8.partialIsValidUtf8 to avoid the copy
+    byte[] bytes;
+    int startIndex;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      startIndex = buffer.arrayOffset() + buffer.position();
+    } else {
+      bytes = toByteArray();
+      startIndex = 0;
+    }
+    return Utf8.partialIsValidUtf8(state, bytes, startIndex, startIndex + size());
+  }
+
+  @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..3fa11c3
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Parser.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 java.io.IOException;
+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..d2f82ac
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -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.
+
+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.
+ */
+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() {
+    list = new ArrayList<E>();
+  }
+  
+  ProtobufArrayList(List<E> toCopy) {
+    list = new ArrayList<E>(toCopy);
+  }
+  
+  ProtobufArrayList(int capacity) {
+    list = new ArrayList<E>(capacity);
+  }
+  
+  @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/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
rename to java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
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..f91cdbc
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
@@ -0,0 +1,702 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 (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/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..8badfab
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -0,0 +1,888 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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 {@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 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) {
+    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 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) {
+    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 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()) {
+      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
+  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 {@code LiteralByteString}.
+     *
+     * @return next non-empty LiteralByteString 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/src/main/java/com/google/protobuf/RpcUtil.java b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcUtil.java
rename to java/core/src/main/java/com/google/protobuf/RpcUtil.java
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/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
rename to java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
diff --git a/java/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/SmallSortedMap.java
rename to java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
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..c99b528
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -0,0 +1,2065 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+              ? 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();
+    }
+
+    /** 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());
+    }
+    
+    /**
+     * 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 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.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
+      } 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);
+      }
+
+      // For historical reasons, fields may optionally be separated by commas or
+      // semicolons.
+      if (!tokenizer.tryConsume(";")) {
+        tokenizer.tryConsume(",");
+      }
+    }
+
+    /**
+     * 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 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.
+
+  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.
+   */
+  public 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.
+   */
+  public 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.
+   */
+  public 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];
+      }
+    });
+  }
+
+  /**
+   * 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 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 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/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..e69de29
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
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/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/UnknownFieldSet.java
rename to java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
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..435ad4d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.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;
+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 an empty {@code UnknownFieldSetLite.Builder}.
+   *
+   * <p>For use by generated code only.
+   */
+  public static Builder newBuilder() {
+    return new Builder();
+  }
+  
+  /**
+   * 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;
+  }
+
+  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;
+  }
+  
+  /**
+   * Builder for {@link UnknownFieldSetLite}s.
+   *
+   * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
+   *
+   * <p>For use by generated code only.
+   */
+  // TODO(dweis): Update the mutable API to no longer need this builder and delete.
+  public static final class Builder {
+
+    private UnknownFieldSetLite set;
+    
+    private Builder() {
+      this.set = null;
+    }
+
+    /**
+     * Ensures internal state is initialized for use.
+     */
+    private void ensureNotBuilt() {
+      if (set == null) {
+        set = new UnknownFieldSetLite();
+      }
+      
+      set.checkMutable();
+    }
+    
+    /**
+     * 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 {
+      ensureNotBuilt();
+      return set.mergeFieldFrom(tag, input);
+    }
+
+    /**
+     * 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.
+     */
+    Builder mergeVarintField(int fieldNumber, int value) {
+      ensureNotBuilt();
+      set.mergeVarintField(fieldNumber, value);
+      return this;
+    }
+    
+    /**
+     * Convenience method for merging a length-delimited field.
+     *
+     * <p>For use by generated code only.
+     */
+    public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
+      ensureNotBuilt();  
+      set.mergeLengthDelimitedField(fieldNumber, value);
+      return this;
+    }
+    
+    /**
+     * Build the {@link UnknownFieldSetLite} 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 an
+     * {@code UnsupportedOperationException} to be thrown.
+     *
+     * <p>For use by generated code only.
+     */
+    public UnknownFieldSetLite build() {
+      if (set == null) {
+        return DEFAULT_INSTANCE;
+      }
+      
+      set.checkMutable();
+      set.makeImmutable();
+
+      return set;
+    }
+  }
+}
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..5257c5a
--- /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 (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/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..f443ee3
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.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;
+
+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);
+    }
+  }
+}
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..48c7e9e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -0,0 +1,481 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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, 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)
+ */
+final class Utf8 {
+  private Utf8() {}
+  
+  /**
+   * 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;
+
+  // 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();
+    }
+  }
+  
+
+  // 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 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 UnpairedSurrogateException((i - 1), utf16Length);
+        }
+        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 UnpairedSurrogateException(i, utf16Length);
+        }
+        throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+      }
+    }
+    return j;
+  }
+  // End Guava UTF-8 methods.
+}
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..8dbe1ae
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/WireFormat.java
@@ -0,0 +1,245 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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) {
+      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);
+
+  /**
+   * 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 {
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readString();
+      }
+    },
+    /** Eagerly parses to String; throws an IOException on invalid bytes. */
+    STRICT {
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readStringRequireUtf8();
+      }
+    },
+    /** Keep data as ByteString; validation/conversion to String is lazy. */
+    LAZY {
+      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/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/AbstractMessageTest.java
rename to java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
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..e169f69
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -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.
+
+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 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..b8ad1fe
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -0,0 +1,469 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testCopyConstructor() {
+    BooleanArrayList copy = new BooleanArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new BooleanArrayList(BooleanArrayList.emptyList());
+    assertEquals(BooleanArrayList.emptyList(), copy);
+    
+    copy = new BooleanArrayList(asList(false, false, true));
+    assertEquals(asList(false, false, true), copy);
+
+    copy = new BooleanArrayList(Collections.<Boolean>emptyList());
+    assertEquals(BooleanArrayList.emptyList(), copy);
+  }
+  
+  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..7a8a0a5
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -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.
+
+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/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
new file mode 100644
index 0000000..5267c16
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -0,0 +1,760 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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]);
+  }
+}
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..3d6381c
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -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.
+
+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/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
rename to java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
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..6018ea5
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -0,0 +1,546 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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 {
+  /**
+   * 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 test 32-bit write if the value fits into an int.
+    if (value == (int) value) {
+      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 test 32-bit write if the value fits into an int.
+      if (value == (int) value) {
+        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());
+      }
+    }
+  }
+
+  private void assertVarintRoundTrip(long value) throws Exception {
+    {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+      output.writeRawVarint64(value);
+      output.flush();
+      byte[] bytes = rawOutput.toByteArray();
+      assertEquals(bytes.length, CodedOutputStream.computeRawVarint64Size(value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(value, input.readRawVarint64());
+    }
+
+    if (value == (int) value) {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+      output.writeRawVarint32((int) value);
+      output.flush();
+      byte[] bytes = rawOutput.toByteArray();
+      assertEquals(bytes.length, CodedOutputStream.computeRawVarint32Size((int) value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(value, input.readRawVarint32());
+    }
+  }
+
+  /** Checks that invariants are maintained for varint round trip input and output. */
+  public void testVarintRoundTrips() throws Exception {
+    assertVarintRoundTrip(0L);
+    for (int bits = 0; bits < 64; bits++) {
+      long value = 1L << bits;
+      assertVarintRoundTrip(value);
+      assertVarintRoundTrip(value + 1);
+      assertVarintRoundTrip(value - 1);
+      assertVarintRoundTrip(-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));
+  }
+
+  /**
+   * 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(Internal.UTF_8);
+    for (int i = 0; i < 1024; ++i) {
+      codedStream.writeRawBytes(value, 0, value.length);
+    }
+    String string =
+        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
+    // Ensure we take the slower fast path.
+    assertTrue(CodedOutputStream.computeRawVarint32Size(string.length())
+        != CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+    
+    codedStream.writeStringNoTag(string);
+    int stringSize = CodedOutputStream.computeStringSizeNoTag(string);
+    
+    // Make sure we have written more bytes than the buffer could hold. This is
+    // to make the test complete.
+    assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
+    
+    // Verify that the total bytes written is correct
+    assertEquals((value.length * 1024) + stringSize, codedStream.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.computeRawVarint32Size(string.length()));
+    assertEquals(
+        2, CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+    assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR);
+    
+    CodedOutputStream output =
+        CodedOutputStream.newInstance(ByteBuffer.allocate(bufferSize), bufferSize);
+    output.writeStringNoTag(string);
+  }
+
+  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(bytes(0x02, 0x33, 0x44, 0x00), destination);
+    assertEquals(3, codedStream.getTotalBytesWritten());
+  }
+  
+  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]);
+    for (String s : invalidStrings) {
+      // TODO(dweis): These should all fail; instead they are corrupting data.
+      CodedOutputStream.computeStringSizeNoTag(s);
+      outputWithStream.writeStringNoTag(s);
+      outputWithArray.writeStringNoTag(s);
+    }
+  }
+  
+  private static String newString(char... chars) {
+    return new String(chars);
+  }
+
+  /** Regression test for https://github.com/google/protobuf/issues/292 */
+  public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
+    String testCase = "Foooooooo";
+    assertEquals(CodedOutputStream.computeRawVarint32Size(testCase.length()),
+        CodedOutputStream.computeRawVarint32Size(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 (int i = 0; i < 11; i++) {
+      CodedOutputStream output = CodedOutputStream.newInstance(new byte[i]);
+      try {
+        output.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 (int i : lengths) {
+      testEncodingOfString('q', i);      // 1 byte per char
+      testEncodingOfString('\u07FF', i); // 2 bytes per char
+      testEncodingOfString('\u0981', i); // 3 bytes per char
+    }
+  }
+
+  private void testEncodingOfString(char c, int length) throws Exception {
+    String fullString = fullString(c, length);
+    TestAllTypes testAllTypes = TestAllTypes.newBuilder()
+        .setOptionalString(fullString)
+        .build();
+    assertEquals(
+        fullString, TestAllTypes.parseFrom(testAllTypes.toByteArray()).getOptionalString());
+  }
+
+  private String fullString(char c, int length) {
+    char[] result = new char[length];
+    Arrays.fill(result, c);
+    return new String(result);
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
rename to java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
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..82ff34a
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -0,0 +1,765 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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..d3deaa0
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -0,0 +1,473 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testCopyConstructor() {
+    DoubleArrayList copy = new DoubleArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new DoubleArrayList(DoubleArrayList.emptyList());
+    assertEquals(DoubleArrayList.emptyList(), copy);
+    
+    copy = new DoubleArrayList(asList(1D, 2D, 3D));
+    assertEquals(asList(1D, 2D, 3D), copy);
+
+    copy = new DoubleArrayList(Collections.<Double>emptyList());
+    assertEquals(DoubleArrayList.emptyList(), copy);
+  }
+  
+  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/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/DynamicMessageTest.java
rename to java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
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..eaeec0b
--- /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, new Class[]{}) != null) {
+        return true;
+      } else {
+        return false;
+      }
+    } catch (NoSuchMethodException e) {
+      return false;
+    }
+  }
+
+  private static boolean isHasMethodRemoved(
+      Class classWithFieldPresence,
+      Class classWithoutFieldPresence,
+      String camelName) {
+    return hasMethod(classWithFieldPresence, "get" + camelName)
+        && hasMethod(classWithFieldPresence, "has" + camelName)
+        && hasMethod(classWithoutFieldPresence, "get" + camelName)
+        && !hasMethod(classWithoutFieldPresence, "has" + camelName);
+  }
+
+  public void testHasMethod() {
+    // Optional non-message fields don't have a hasFoo() method generated.
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalInt32"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalString"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalBytes"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalNestedEnum"));
+
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalInt32"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalString"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalBytes"));
+    assertTrue(isHasMethodRemoved(
+        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).
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofUint32"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofString"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofBytes"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofNestedMessage"));
+
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofUint32"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofString"));
+    assertTrue(isHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofBytes"));
+    assertTrue(isHasMethodRemoved(
+        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..a5e6542
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -0,0 +1,473 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testCopyConstructor() {
+    FloatArrayList copy = new FloatArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new FloatArrayList(FloatArrayList.emptyList());
+    assertEquals(FloatArrayList.emptyList(), copy);
+    
+    copy = new FloatArrayList(asList(1F, 2F, 3F));
+    assertEquals(asList(1F, 2F, 3F), copy);
+
+    copy = new FloatArrayList(Collections.<Float>emptyList());
+    assertEquals(FloatArrayList.emptyList(), copy);
+  }
+  
+  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/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
rename to java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
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..70812b9
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -0,0 +1,1661 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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);
+    }
+  }
+
+  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..3733eb3
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -0,0 +1,473 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testCopyConstructor() {
+    IntArrayList copy = new IntArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new IntArrayList(IntArrayList.emptyList());
+    assertEquals(IntArrayList.emptyList(), copy);
+    
+    copy = new IntArrayList(asList(1, 2, 3));
+    assertEquals(asList(1, 2, 3), copy);
+
+    copy = new IntArrayList(Collections.<Integer>emptyList());
+    assertEquals(IntArrayList.emptyList(), copy);
+  }
+
+  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..8751baa
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -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.
+
+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 {
+    // Travis' OOM killer doesn't like this test
+    if (System.getenv("TRAVIS") == null) {
+      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/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..321669f
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -0,0 +1,420 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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)
+ */
+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, 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 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 = 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 = 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/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyFieldTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
diff --git a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
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/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
rename to java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
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..b1f298f
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -0,0 +1,1462 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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.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 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());
+  }
+  
+  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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on foreignMessage.
+    assertEquals(3, builder.getOptionalForeignMessage().getC());
+    messageAfterBuild = builder.build();
+    assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    builder.clearOptionalForeignMessage();
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getOptionalForeignMessage());
+    assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on optionalGroup.
+    assertEquals(3, builder.getOptionalGroup().getA());
+    messageAfterBuild = builder.build();
+    assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    builder.clearOptionalGroup();
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property.
+    assertEquals(3, builder.getOptionalLazyMessage().getBb());
+    messageAfterBuild = builder.build();
+    assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    builder.clearOptionalLazyMessage();
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property.
+    assertEquals(3, messageAfterBuild.getRepeatedForeignMessage(0).getC());
+    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));
+    // LITE_RUNTIME doesn't implement equals so we compare on a property.
+    assertEquals(3, builder.getRepeatedForeignMessage(0).getC());
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
+    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());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
+    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));
+  }
+}
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..68b55ce
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -0,0 +1,495 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 {@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) {
+    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 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";
+    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..1bd094f
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -0,0 +1,473 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testCopyConstructor() {
+    LongArrayList copy = new LongArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new LongArrayList(LongArrayList.emptyList());
+    assertEquals(LongArrayList.emptyList(), copy);
+    
+    copy = new LongArrayList(asList(1L, 2L, 3L));
+    assertEquals(asList(1L, 2L, 3L), copy);
+
+    copy = new LongArrayList(Collections.<Long>emptyList());
+    assertEquals(LongArrayList.emptyList(), copy);
+  }
+  
+  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..3d8c9bc
--- /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..1fa3cbd
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -0,0 +1,684 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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..0e5c128
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -0,0 +1,783 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/MessageTest.java
rename to java/core/src/test/java/com/google/protobuf/MessageTest.java
diff --git a/java/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/NestedBuildersTest.java
rename to java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
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..e40a366
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.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 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.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 static final ByteBuffer BUFFER = ByteBuffer.wrap(BYTES.clone());
+  private static final ByteString TEST_STRING = new NioByteString(BUFFER);
+
+  public void testExpectedType() {
+    String actualClassName = getActualClassName(TEST_STRING);
+    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] == TEST_STRING.byteAt(i));
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
+  }
+
+  public void testByteIterator() {
+    boolean stillEqual = true;
+    ByteString.ByteIterator iter = TEST_STRING.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 : TEST_STRING) {
+      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,
+        TEST_STRING.size());
+  }
+
+  public void testGetTreeDepth() {
+    assertEquals(CLASSNAME + " must have depth 0", 0, TEST_STRING.getTreeDepth());
+  }
+
+  public void testIsBalanced() {
+    assertTrue(CLASSNAME + " is technically balanced", TEST_STRING.isBalanced());
+  }
+
+  public void testCopyTo_ByteArrayOffsetLength() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+    int sourceOffset = 213;
+    TEST_STRING.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
+      TEST_STRING.copyTo(destination, TEST_STRING.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
+      TEST_STRING.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
+      TEST_STRING.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
+      TEST_STRING.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
+      TEST_STRING.copyTo(destination, 2 * TEST_STRING.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
+      TEST_STRING.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);
+    TEST_STRING.copyTo(myBuffer);
+    myBuffer.flip();
+    assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes",
+        BUFFER, myBuffer);
+
+    // Target buffer bigger than required.
+    myBuffer = ByteBuffer.allocate(TEST_STRING.size() + 1);
+    TEST_STRING.copyTo(myBuffer);
+    myBuffer.flip();
+    assertEquals(BUFFER, myBuffer);
+
+    // Target buffer has no space.
+    myBuffer = ByteBuffer.allocate(0);
+    try {
+      TEST_STRING.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 {
+      TEST_STRING.copyTo(myBuffer);
+      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+    } catch (BufferOverflowException e) {
+      // Expected.
+    }
+  }
+
+  public void testMarkSupported() {
+    InputStream stream = TEST_STRING.newInput();
+    assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported());
+  }
+
+  public void testMarkAndReset() throws IOException {
+    int fraction = TEST_STRING.size() / 3;
+
+    InputStream stream = TEST_STRING.newInput();
+    stream.mark(TEST_STRING.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",
+        (TEST_STRING.size() - fraction), stream.available());
+    stream.reset();
+    assertEquals(
+        CLASSNAME + ": after resetting, all bytes are available",
+        TEST_STRING.size(), stream.available());
+
+    skipFully(stream, TEST_STRING.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 = TEST_STRING.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 = TEST_STRING.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 = TEST_STRING.toByteArray();
+    assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testWriteTo() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    TEST_STRING.writeTo(bos);
+    byte[] roundTripBytes = bos.toByteArray();
+    assertTrue(CLASSNAME + ".writeTo() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testNewOutput() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    ByteString.Output output = ByteString.newOutput();
+    TEST_STRING.writeTo(output);
+    assertEquals("Output Size returns correct result",
+        output.size(), TEST_STRING.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",
+        TEST_STRING.concat(TEST_STRING), 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 {
+      TEST_STRING.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
+  public void testEquals() {
+    assertEquals(CLASSNAME + " must not equal null", false, TEST_STRING.equals(null));
+    assertEquals(CLASSNAME + " must equal self", TEST_STRING, TEST_STRING);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        TEST_STRING.equals(EMPTY));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        EMPTY, TEST_STRING.substring(55, 55));
+    assertEquals(CLASSNAME + " must equal another string with the same value",
+        TEST_STRING, new NioByteString(BUFFER));
+
+    byte[] mungedBytes = mungedBytes();
+    assertFalse(CLASSNAME + " must not equal every string with the same length",
+        TEST_STRING.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
+  }
+
+  public void testEqualsLiteralByteString() {
+    ByteString literal = ByteString.copyFrom(BYTES);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal,
+        TEST_STRING);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", TEST_STRING,
+        literal);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        TEST_STRING.equals(ByteString.EMPTY));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        ByteString.EMPTY, TEST_STRING.substring(55, 55));
+
+    literal = ByteString.copyFrom(mungedBytes());
+    assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
+        TEST_STRING.equals(literal));
+    assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
+        literal.equals(TEST_STRING));
+  }
+
+  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,
+        TEST_STRING);
+    assertEquals(CLASSNAME + " must equal RopeByteString with same value", TEST_STRING,
+        rope);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        TEST_STRING.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        ByteString.EMPTY.concat(ByteString.EMPTY), TEST_STRING.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",
+        TEST_STRING.equals(rope));
+    assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
+        rope.equals(TEST_STRING));
+  }
+
+  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 = TEST_STRING.hashCode();
+    assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash);
+  }
+
+  public void testPeekCachedHashCode() {
+    ByteString newString = new NioByteString(BUFFER);
+    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 = TEST_STRING.partialHash(TEST_STRING.size(), 0, TEST_STRING.size());
+    assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode",
+        EXPECTED_HASH, hash);
+  }
+
+  public void testNewInput() throws IOException {
+    InputStream input = TEST_STRING.newInput();
+    assertEquals("InputStream.available() returns correct value",
+        TEST_STRING.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 = TEST_STRING.newInput();
+    int stringSize = TEST_STRING.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()",
+        TEST_STRING.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()",
+        TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+  }
+
+  public void testNewCodedInput() throws IOException {
+    CodedInputStream cis = TEST_STRING.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,
+        TEST_STRING.concat(EMPTY), TEST_STRING);
+    assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME,
+        EMPTY.concat(TEST_STRING), TEST_STRING);
+  }
+
+  public void testJavaSerialization() throws Exception {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    ObjectOutputStream oos = new ObjectOutputStream(out);
+    oos.writeObject(TEST_STRING);
+    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", TEST_STRING, 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..37fa242
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -0,0 +1,211 @@
+package com.google.protobuf;
+
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * 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)
+ */
+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() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(in);
+      }
+    });
+  }
+
+  @Test public void message_parseFrom_InputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
+      }
+    });
+  }
+
+  @Test public void message_parseFrom_CodedInputStream() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
+      }
+    });
+  }
+
+  @Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      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() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseDelimitedFrom(in);
+      }
+    });
+  }
+
+  @Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() {
+    setupDelimited();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeFrom_InputStream() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.newBuilder().mergeFrom(in).build();
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      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() {
+      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() {
+      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() {
+      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() {
+      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..5a92bac
--- /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.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/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..245c3de
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
@@ -0,0 +1,303 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testCopyConstructor() {
+    ProtobufArrayList<Integer> copy = new ProtobufArrayList<Integer>(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new ProtobufArrayList<Integer>(IntArrayList.emptyList());
+    assertEquals(ProtobufArrayList.emptyList(), copy);
+    
+    copy = new ProtobufArrayList<Integer>(asList(1, 2, 3));
+    assertEquals(asList(1, 2, 3), copy);
+
+    copy = new ProtobufArrayList<Integer>(Collections.<Integer>emptyList());
+    assertEquals(ProtobufArrayList.emptyList(), copy);
+  }
+  
+  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/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/ServiceTest.java
rename to java/core/src/test/java/com/google/protobuf/ServiceTest.java
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/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
rename to java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
diff --git a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
rename to java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
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..01acb88
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -0,0 +1,4275 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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) {
+    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 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 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 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"));
+  }
+
+  /**
+   * 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();
+  }
+
+  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/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..1df4fad
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -0,0 +1,1021 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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;
+
+/**
+ * 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));
+
+    // 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_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());
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
rename to java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
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..dc98737
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -0,0 +1,368 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 testNoDataIsDefaultInstance() {
+    assertSame(
+        UnknownFieldSetLite.getDefaultInstance(),
+        UnknownFieldSetLite.newBuilder()
+            .build());
+  }
+  
+  public void testBuilderReuse() throws IOException {
+    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+    builder.mergeVarintField(10, 2);
+    builder.build();
+
+    try {
+      builder.build();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // Expected.
+    }
+
+    try {
+      builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // Expected.
+    }
+
+    try {
+      builder.mergeVarintField(5, 1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // Expected.
+    }
+  }
+
+  public void testBuilderReuse_empty() {
+    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+    builder.build();
+    builder.build();
+  }
+  
+  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..8c9dcaf
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -0,0 +1,653 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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..0175005
--- /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 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.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
+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/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/src/test/java/com/google/protobuf/lazy_fields_lite.proto b/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
rename to java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
diff --git a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto
rename to java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
diff --git a/java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto
rename to java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
diff --git a/java/src/test/java/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/map_for_proto2_test.proto
rename to java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
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/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/multiple_files_test.proto
rename to java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto
diff --git a/java/src/test/java/com/google/protobuf/nested_builders_test.proto b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/nested_builders_test.proto
rename to java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
diff --git a/java/src/test/java/com/google/protobuf/nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/nested_extension.proto
rename to java/core/src/test/proto/com/google/protobuf/nested_extension.proto
diff --git a/java/src/test/java/com/google/protobuf/nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/nested_extension_lite.proto
rename to java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/non_nested_extension.proto
rename to java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto
rename to java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/outer_class_name_test.proto
rename to java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/outer_class_name_test2.proto
rename to java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/outer_class_name_test3.proto
rename to java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
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/src/test/java/com/google/protobuf/test_check_utf8.proto b/java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_check_utf8.proto
rename to java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto b/java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_check_utf8_size.proto
rename to java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto
diff --git a/java/src/test/java/com/google/protobuf/test_custom_options.proto b/java/core/src/test/proto/com/google/protobuf/test_custom_options.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_custom_options.proto
rename to java/core/src/test/proto/com/google/protobuf/test_custom_options.proto
diff --git a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto b/java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_extra_interfaces.proto
rename to java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
new file mode 100644
index 0000000..70c7d04
--- /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-2</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="${core.root}/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="${core.root}/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.dir}</generatedSourcesDirectory>
+          <generatedTestSourcesDirectory>${generated.testsources.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 3eb7a70..d5719ed 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -8,17 +8,33 @@
     <artifactId>google</artifactId>
     <version>1</version>
   </parent>
+
   <groupId>com.google.protobuf</groupId>
-  <artifactId>protobuf-java</artifactId>
-  <version>3.0.0-alpha-3-pre</version>
-  <packaging>bundle</packaging>
-  <name>Protocol Buffer Java API</name>
+  <artifactId>protobuf-parent</artifactId>
+  <version>3.0.0-beta-2</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>
+  </properties>
+
   <licenses>
     <license>
       <name>New BSD license</name>
@@ -26,173 +42,116 @@
       <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.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>
+      <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" />
-                  <arg value="src/test/java/com/google/protobuf/field_presence_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_for_proto2_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_test.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-3-pre</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>release</id>
       <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>
+            <version>1.6</version>
             <executions>
               <execution>
                 <id>sign-artifacts</id>
@@ -206,79 +165,23 @@
           <plugin>
             <groupId>org.sonatype.plugins</groupId>
             <artifactId>nexus-staging-maven-plugin</artifactId>
-            <version>1.6.3</version>
+            <version>1.6.6</version>
             <extensions>true</extensions>
             <configuration>
-               <serverId>sonatype-nexus-staging</serverId>
-               <nexusUrl>https://oss.sonatype.org/</nexusUrl>
-               <autoReleaseAfterClose>false</autoReleaseAfterClose>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-    <profile>
-      <id>lite</id>
-      <build>
-        <plugins>
-          <plugin>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/AbstractMessageLite.java</include>
-                <include>**/AbstractParser.java</include>
-                <include>**/BoundedByteString.java</include>
-                <include>**/ByteString.java</include>
-                <include>**/CodedInputStream.java</include>
-                <include>**/CodedOutputStream.java</include>
-                <include>**/ExtensionLite.java</include>
-                <include>**/ExtensionRegistryLite.java</include>
-                <include>**/FieldSet.java</include>
-                <include>**/GeneratedMessageLite.java</include>
-                <include>**/Internal.java</include>
-                <include>**/InvalidProtocolBufferException.java</include>
-                <include>**/LazyFieldLite.java</include>
-                <include>**/LazyStringArrayList.java</include>
-                <include>**/LazyStringList.java</include>
-                <include>**/LiteralByteString.java</include>
-                <include>**/MapEntryLite.java</include>
-                <include>**/MapFieldLite.java</include>
-                <include>**/MessageLite.java</include>
-                <include>**/MessageLiteOrBuilder.java</include>
-                <include>**/Parser.java</include>
-                <include>**/ProtocolStringList.java</include>
-                <include>**/RopeByteString.java</include>
-                <include>**/SmallSortedMap.java</include>
-                <include>**/UninitializedMessageException.java</include>
-                <include>**/UnknownFieldSetLite.java</include>
-                <include>**/UnmodifiableLazyStringList.java</include>
-                <include>**/Utf8.java</include>
-                <include>**/WireFormat.java</include>
-              </includes>
-              <testIncludes>
-                <testInclude>**/*Lite.java</testInclude>
-                <testInclude>**/LazyMessageLiteTest.java</testInclude>
-                <testInclude>**/LiteTest.java</testInclude>
-                <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
-              </testIncludes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-surefire-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/*Test.java</include>
-              </includes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-jar-plugin</artifactId>
-            <configuration>
-              <classifier>lite</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/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java
deleted file mode 100644
index cc89173..0000000
--- a/java/src/main/java/com/google/protobuf/AbstractMessage.java
+++ /dev/null
@@ -1,524 +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.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 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, getAllFields(), output, false);
-  }
-
-  protected int memoizedSize = -1;
-
-  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");
-    result.put(entry.getField(key), entry.getField(value));
-    while (iterator.hasNext()) {
-      entry = (Message) iterator.next();
-      result.put(entry.getField(key), entry.getField(value));
-    }
-    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>
-      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 Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
-        int index) {
-      throw new UnsupportedOperationException(
-          "getRepeatedFieldBuilder() 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/BoundedByteString.java b/java/src/main/java/com/google/protobuf/BoundedByteString.java
deleted file mode 100644
index b4c3fb1..0000000
--- a/java/src/main/java/com/google/protobuf/BoundedByteString.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 java.io.IOException;
-import java.io.InvalidObjectException;
-import java.io.ObjectInputStream;
-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);
-  }
-
-  // =================================================================
-  // Serializable
-
-  private static final long serialVersionUID = 1L;
-
-  Object writeReplace() {
-    return new LiteralByteString(toByteArray());
-  }
-
-  private void readObject(ObjectInputStream in) throws IOException {
-    throw new InvalidObjectException(
-        "BoundedByteStream instances are not to be serialized directly");
-  }
-
-  // =================================================================
-  // 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 9b0a524..0000000
--- a/java/src/main/java/com/google/protobuf/ByteString.java
+++ /dev/null
@@ -1,1026 +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.Serializable;
-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>, 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
-
-  // Defined by java.nio.charset.Charset
-  protected static final String UTF_8 = "UTF-8";
-
-  /**
-   * 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 0ca00ba..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)) < 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) {
-    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 806f46c..0000000
--- a/java/src/main/java/com/google/protobuf/Descriptors.java
+++ /dev/null
@@ -1,2353 +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.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;
-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));
-    }
-
-    /** 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.
-     */
-    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));
-      }
-    }
-    
-    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. */
-    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());
-    }
-
-    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? */
-    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();
-    }
-
-    @Override
-    public String toString() {
-      return getFullName();
-    }
-
-    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));
-    }
-    
-    /**
-     * 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. */
-    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);
-    }
-    
-    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. */
-    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/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
deleted file mode 100644
index 9457d99..0000000
--- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ /dev/null
@@ -1,2699 +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 com.google.protobuf.Descriptors.FileDescriptor;
-import com.google.protobuf.Descriptors.OneofDescriptor;
-import com.google.protobuf.GeneratedMessageLite.ExtendableMessage;
-import com.google.protobuf.GeneratedMessageLite.GeneratedExtension;
-
-import java.io.IOException;
-import java.io.ObjectStreamException;
-import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-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();
-  }
-
-  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 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;
-    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)) {
-          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 (Java 1.6 override semantics, but we must support 1.5)
-  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 (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);
-  }
-
-  /**
-   * 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 (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);
-  }
-
-  @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>
-      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.
-     */
-    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 Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
-        int index) {
-      return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
-          this, index);
-    }
-
-    //@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 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 (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;
-      }
-    }
-
-    /**
-     * 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.
-    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 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 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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (Java 1.6 override semantics, but we must support 1.5)
-    @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 (Java 1.6 override semantics, but we must support 1.5)
-    @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.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 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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (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);
-      }
-    }
-  }
-
-  /**
-   * 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();
-      }
-
-      public Object get(final GeneratedMessage message) {
-        return invokeOrDie(getMethod, message);
-      }
-      public Object get(GeneratedMessage.Builder builder) {
-        return invokeOrDie(getMethodBuilder, builder);
-      }
-      public Object getRaw(final GeneratedMessage message) {
-        return get(message);
-      }
-      public Object getRaw(GeneratedMessage.Builder builder) {
-        return get(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 getRepeatedRaw(final GeneratedMessage message,
-                                final int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedFieldRaw() called on a singular field.");
-      }
-      public Object getRepeated(GeneratedMessage.Builder builder, int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedField() called on a singular field.");
-      }
-      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
-          int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedFieldRaw() 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.");
-      }
-      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);
-      }
-
-      public Object get(final GeneratedMessage message) {
-        return invokeOrDie(getMethod, message);
-      }
-      public Object get(GeneratedMessage.Builder builder) {
-        return invokeOrDie(getMethodBuilder, builder);
-      }
-      public Object getRaw(final GeneratedMessage message) {
-        return get(message);
-      }
-      public Object getRaw(GeneratedMessage.Builder builder) {
-        return get(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 Object getRepeatedRaw(GeneratedMessage message, int index) {
-        return getRepeated(message, index);
-      }
-      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
-          int index) {
-        return getRepeated(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.");
-      }
-      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());
-      }
-
-      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);
-      }
-
-      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);
-      }
-
-      public Object getRaw(GeneratedMessage message) {
-        return get(message);
-      }
-
-      public Object getRaw(GeneratedMessage.Builder builder) {
-        return get(builder);
-      }
-
-      public void set(Builder builder, Object value) {
-        clear(builder);
-        for (Object entry : (List) value) {
-          addRepeated(builder, entry);
-        }
-      }
-
-      public Object getRepeated(GeneratedMessage message, int index) {
-        return getMapField(message).getList().get(index);
-      }
-
-      public Object getRepeated(Builder builder, int index) {
-        return getMapField(builder).getList().get(index);
-      }
-
-      public Object getRepeatedRaw(GeneratedMessage message, int index) {
-        return getRepeated(message, index);
-      }
-
-      public Object getRepeatedRaw(Builder builder, int index) {
-        return getRepeated(builder, index);
-      }
-
-      public void setRepeated(Builder builder, int index, Object value) {
-        getMutableMapField(builder).getMutableList().set(index, (Message) value);
-      }
-
-      public void addRepeated(Builder builder, Object value) {
-        getMutableMapField(builder).getMutableList().add((Message) value);
-      }
-
-      public boolean has(GeneratedMessage message) {
-        throw new UnsupportedOperationException(
-            "hasField() is not supported for repeated fields.");
-      }
-
-      public boolean has(Builder builder) {
-        throw new UnsupportedOperationException(
-            "hasField() is not supported for repeated fields.");
-      }
-
-      public int getRepeatedCount(GeneratedMessage message) {
-        return getMapField(message).getList().size();
-      }
-
-      public int getRepeatedCount(Builder builder) {
-        return getMapField(builder).getList().size();
-      }
-
-      public void clear(Builder builder) {
-        getMutableMapField(builder).getMutableList().clear();
-      }
-
-      public com.google.protobuf.Message.Builder newBuilder() {
-        return mapEntryMessageDefaultInstance.newBuilderForType();
-      }
-
-      public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
-        throw new UnsupportedOperationException(
-            "Nested builder not supported for map fields.");
-      }
-
-      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;
-  }
-}
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 6839c9d..0000000
--- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ /dev/null
@@ -1,1116 +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.WireFormat.FieldType;
-
-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.concurrent.ConcurrentHashMap;
-
-/**
- * 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
-        implements Serializable {
-  
-  /**
-   * Holds all the {@link PrototypeHolder}s for loaded classes.
-   */
-  // TODO(dweis): Consider different concurrency values.
-  // TODO(dweis): This will prevent garbage collection of the class loader.
-  //     Ideally we'd use something like ClassValue but that's Java 7 only.
-  private static final Map<Class<?>, PrototypeHolder<?, ?>> PROTOTYPE_MAP =
-      new ConcurrentHashMap<Class<?>, PrototypeHolder<?, ?>>();
-  
-  // For use by generated code only.
-  protected static <
-      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-      BuilderType extends GeneratedMessageLite.Builder<
-          MessageType, BuilderType>> void onLoad(Class<MessageType> clazz,
-              PrototypeHolder<MessageType, BuilderType> protoTypeHolder) {
-    PROTOTYPE_MAP.put(clazz, protoTypeHolder);
-  }
-
-  private static final long serialVersionUID = 1L;
-
-  /** For use by generated code only.  */
-  protected UnknownFieldSetLite unknownFields;
-  
-  @SuppressWarnings("unchecked") // Guaranteed by runtime.
-  public final Parser<MessageType> getParserForType() {
-    return (Parser<MessageType>) PROTOTYPE_MAP
-        .get(getClass()).getParserForType();
-  }
-
-  @SuppressWarnings("unchecked") // Guaranteed by runtime.
-  public final MessageType getDefaultInstanceForType() {
-    return (MessageType) PROTOTYPE_MAP
-        .get(getClass()).getDefaultInstanceForType();
-  }
-
-  @SuppressWarnings("unchecked") // Guaranteed by runtime.
-  public final BuilderType newBuilderForType() {
-    return (BuilderType) PROTOTYPE_MAP
-        .get(getClass()).newBuilderForType();
-  }
-
-  /**
-   * 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 static boolean parseUnknownField(
-      CodedInputStream input,
-      UnknownFieldSetLite.Builder unknownFields,
-      ExtensionRegistryLite extensionRegistry,
-      int tag) throws IOException {
-    return unknownFields.mergeFieldFrom(tag, input);
-  }
-
-  // The default behavior. If a message has required fields in its subtree, the
-  // generated code will override.
-  public boolean isInitialized() {
-    return true;
-  }
-
-  @SuppressWarnings("unchecked")
-  public abstract static class Builder<
-      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-      BuilderType extends Builder<MessageType, BuilderType>>
-          extends AbstractMessageLite.Builder<BuilderType> {
-
-    private final MessageType defaultInstance;
-
-    /** For use by generated code only. */
-    protected UnknownFieldSetLite unknownFields =
-        UnknownFieldSetLite.getDefaultInstance();
-
-    protected Builder(MessageType defaultInstance) {
-      this.defaultInstance = defaultInstance;
-    }
-
-    // The default behavior. If a message has required fields in its subtree,
-    // the generated code will override.
-    public boolean isInitialized() {
-      return true;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public BuilderType clear() {
-      unknownFields = UnknownFieldSetLite.getDefaultInstance();
-      return (BuilderType) this;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public BuilderType clone() {
-      BuilderType builder =
-          (BuilderType) getDefaultInstanceForType().newBuilderForType();
-      builder.mergeFrom(buildPartial());
-      return builder;
-    }
-
-    /** All subclasses implement this. */
-    public abstract MessageType buildPartial();
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final MessageType build() {
-      MessageType result = buildPartial();
-      if (!result.isInitialized()) {
-        throw newUninitializedMessageException(result);
-      }
-      return result;
-    }
-
-    /** All subclasses implement this. */
-    public abstract BuilderType mergeFrom(MessageType message);
-    
-    public MessageType getDefaultInstanceForType() {
-      return defaultInstance;
-    }
-
-    /**
-     * Called by subclasses to parse an unknown field.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    protected boolean parseUnknownField(
-        CodedInputStream input,
-        UnknownFieldSetLite.Builder unknownFields,
-        ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      return unknownFields.mergeFieldFrom(tag, input);
-    }
-
-    /**
-     * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
-     * message.
-     *
-     * <p>For use by generated code only.
-     */
-    protected final BuilderType mergeUnknownFields(
-        final UnknownFieldSetLite unknownFields) {
-      this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields);
-      return (BuilderType) this;
-    }
-    
-    public BuilderType mergeFrom(
-        com.google.protobuf.CodedInputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      MessageType parsedMessage = null;
-      try {
-        parsedMessage =
-            (MessageType) getDefaultInstanceForType().getParserForType().parsePartialFrom(
-                input, extensionRegistry);
-      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-        parsedMessage = (MessageType) e.getUnfinishedMessage();
-        throw e;
-      } finally {
-        if (parsedMessage != null) {
-          mergeFrom(parsedMessage);
-        }
-      }
-      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();
-
-    // -1 => not memoized, 0 => false, 1 => true.
-    private byte memoizedIsInitialized = -1;
-
-    // The default behavior. If a message has required fields in its subtree,
-    // the generated code will override.
-    public boolean isInitialized() {
-      if (memoizedIsInitialized == -1) {
-        memoizedIsInitialized = (byte) (extensions.isInitialized() ? 1 : 0);
-      }
-
-      return memoizedIsInitialized == 1;
-    }
-
-    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 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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (Java 1.6 override semantics, but we must support 1.5)
-    @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 (Java 1.6 override semantics, but we must support 1.5)
-    @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();
-    }
-
-
-    /**
-     * Used by parsing constructors in generated classes.
-     */
-    protected static void makeExtensionsImmutable(
-        FieldSet<ExtensionDescriptor> extensions) {
-      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);
-    }
-
-    private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
-    private boolean extensionsIsMutable;
-
-    // The default behavior. If a message has required fields in its subtree,
-    // the generated code will override.
-    public boolean isInitialized() {
-      return extensions.isInitialized();
-    }
-
-    // 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.
-     * <p>
-     * For use by generated code only.
-     */
-    protected final 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 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 (Java 1.6 override semantics, but we must support 1.5)
-    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 (Java 1.6 override semantics, but we must support 1.5)
-    @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. */
-    @SuppressWarnings("unchecked")
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    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));
-    }
-
-    // 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);
-      ensureExtensionsIsMutable();
-      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);
-      ensureExtensionsIsMutable();
-      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);
-      ensureExtensionsIsMutable();
-      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);
-      ensureExtensionsIsMutable();
-      extensions.clearField(extensionLite.descriptor);
-      return (BuilderType) this;
-    }
-
-    /** Called by subclasses to check if all extensions are initialized. */
-    protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
-    }
-
-    protected final void mergeExtensionFields(final MessageType other) {
-      ensureExtensionsIsMutable();
-      extensions.mergeFrom(((ExtendableMessage) other).extensions);
-    }
-  }
-
-  //-----------------------------------------------------------------
-
-  /**
-   * Parse an unknown field or an extension. For use by generated code only.
-   * @return {@code true} unless the tag is an end-group tag.
-   */
-  protected static <MessageType extends MessageLite>
-      boolean parseUnknownField(
-          FieldSet<ExtensionDescriptor> extensions,
-          MessageType defaultInstance,
-          CodedInputStream input,
-          UnknownFieldSetLite.Builder unknownFields,
-          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 unknownFields.mergeFieldFrom(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) {
-            unknownFields.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;
-  }
-
-  // -----------------------------------------------------------------
-
-  /** 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>
-          extends ExtensionLite<ContainingType, 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;
-      }
-    }
-
-    public FieldType getLiteType() {
-      return descriptor.getLiteType();
-    }
-
-    public boolean isRepeated() {
-      return descriptor.isRepeated;
-    }
-
-    public Type getDefaultValue() {
-      return defaultValue;
-    }
-  }
-
-  /**
-   * 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 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);
-        Parser<?> parser =
-            (Parser<?>) messageClass.getField("PARSER").get(null);
-        return parser.parsePartialFrom(asBytes);
-      } catch (ClassNotFoundException e) {
-        throw new RuntimeException("Unable to find proto buffer class", e);
-      } catch (NoSuchFieldException e) {
-        throw new RuntimeException("Unable to find PARSER", e);
-      } catch (SecurityException e) {
-        throw new RuntimeException("Unable to call PARSER", e);
-      } catch (IllegalAccessException e) {
-        throw new RuntimeException("Unable to call parseFrom method", e);
-      } 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);
-  }
-  
-  /**
-   * 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;
-  }
-  
-  /**
-   * Represents the state needed to implement *ForType methods. Generated code
-   * must provide a static singleton instance by adding it with
-   * {@link GeneratedMessageLite#onLoad(Class, PrototypeHolder)} on class load.
-   * <ul>
-   * <li>{@link #getDefaultInstanceForType()}
-   * <li>{@link #getParserForType()}
-   * <li>{@link #newBuilderForType()}
-   * </ul>
-   * This allows us to trade three generated methods for a static Map.
-   */
-  protected static class PrototypeHolder<
-      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-      BuilderType extends GeneratedMessageLite.Builder<
-          MessageType, BuilderType>> {
-    
-    private final MessageType defaultInstance;
-    private final Parser<MessageType> parser;
-    
-    public PrototypeHolder(
-        MessageType defaultInstance, Parser<MessageType> parser) {
-      this.defaultInstance = defaultInstance;
-      this.parser = parser;
-    }
-    
-    public MessageType getDefaultInstanceForType() {
-      return defaultInstance;
-    }
-
-    public Parser<MessageType> getParserForType() {
-      return parser;
-    }
-
-    @SuppressWarnings("unchecked") // Guaranteed by runtime.
-    public BuilderType newBuilderForType() {
-      return (BuilderType) defaultInstance.toBuilder();
-    }
-  }
-}
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 5a0de6d..0000000
--- a/java/src/main/java/com/google/protobuf/Internal.java
+++ /dev/null
@@ -1,561 +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.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.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 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 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 LiteralByteString.hashCode(bytes);
-  }
-  
-  /**
-   * 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 = 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);
-  
-  /** 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 List<T> around a 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 Map<K, RealValue> and provide a 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>() {
-        public T doForward(Integer value) {
-          T result = enumMap.findValueByNumber(value);
-          return result == null ? unrecognizedValue : result;
-        }
-        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);
-      }
-    }
-  }
-}
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/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
deleted file mode 100644
index 2d40a51..0000000
--- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ /dev/null
@@ -1,371 +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(int intialCapacity) {
-    list = new ArrayList<Object>(intialCapacity);
-  }
-
-  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 6893ddf..0000000
--- a/java/src/main/java/com/google/protobuf/LiteralByteString.java
+++ /dev/null
@@ -1,377 +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 {
-
-  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 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 {
-    // Optimize for empty strings, but ensure we don't silently ignore invalid
-    // encodings.
-    return size() == 0 && UTF_8.equals(charsetName)
-        ? ""
-        : 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) {
-      LiteralByteString otherAsLiteral = (LiteralByteString) other;
-      // If we know the hash codes and they are not equal, we know the byte
-      // strings are not equal.
-      if (hash != 0 
-          && otherAsLiteral.hash != 0 
-          && hash != otherAsLiteral.hash) {
-        return false;
-      }
-      
-      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/MapField.java b/java/src/main/java/com/google/protobuf/MapField.java
deleted file mode 100644
index 82906d3..0000000
--- a/java/src/main/java/com/google/protobuf/MapField.java
+++ /dev/null
@@ -1,259 +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.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-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> {
-  /**
-   * 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 StorageMode mode;
-  private Map<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;
-    }
-    
-    public Message convertKeyAndValueToMessage(K key, V value) {
-      return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
-    }
-    
-    public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
-      MapEntry<K, V> entry = (MapEntry<K, V>) message;
-      map.put(entry.getKey(), entry.getValue());
-    }
-
-    public Message getMessageDefaultInstance() {
-      return defaultEntry;
-    }
-  }
-  
-
-  private final Converter<K, V> converter;
-  
-  private MapField(
-      Converter<K, V> converter,
-      StorageMode mode,
-      Map<K, V> mapData,
-      List<Message> listData) {
-    this.converter = converter;
-    this.mode = mode;
-    this.mapData = mapData;
-    this.listData = listData;
-  }
-    
-  private MapField(
-      MapEntry<K, V> defaultEntry,
-      StorageMode mode,
-      Map<K, V> mapData,
-      List<Message> listData) {
-    this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData, listData);
-  }
-  
-  
-  /** 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(), null);
-  }
-  
-  
-  /** 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 HashMap<K, V>(), null);
-  }
-  
-  
-  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(Map<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 Map<K, V> convertListToMap(List<Message> listData) {
-    Map<K, V> mapData = new HashMap<K, V>();
-    for (Message item : listData) {
-      convertMessageToKeyAndValue(item, mapData);
-    }
-    return 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 HashMap<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()), null);
-  }
-  
-  /** 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();
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/MapFieldLite.java b/java/src/main/java/com/google/protobuf/MapFieldLite.java
deleted file mode 100644
index 7f94c69..0000000
--- a/java/src/main/java/com/google/protobuf/MapFieldLite.java
+++ /dev/null
@@ -1,182 +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.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 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 class MapFieldLite<K, V> {
-  private Map<K, V> mapData;
-  
-  private MapFieldLite(Map<K, V> mapData) {
-    this.mapData = mapData;
-  }
-  
-  @SuppressWarnings({"rawtypes", "unchecked"})
-  private static final MapFieldLite EMPTY_MAP_FIELD =
-      new MapFieldLite(Collections.emptyMap());
-  
-  /** 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 HashMap<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 LiteralByteString.hashCode((byte[]) a);
-    }
-    if (a instanceof Internal.EnumLite) {
-      return Internal.hashEnum((Internal.EnumLite) a);
-    }
-    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 HashMap<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));
-  }
-}
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 fa0265e..0000000
--- a/java/src/main/java/com/google/protobuf/Message.java
+++ /dev/null
@@ -1,263 +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>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.)
-    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/Parser.java b/java/src/main/java/com/google/protobuf/Parser.java
deleted file mode 100644
index 227c02b..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 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/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
deleted file mode 100644
index be737b1..0000000
--- a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
+++ /dev/null
@@ -1,702 +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 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
-  // 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 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 (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 168bcce..0000000
--- a/java/src/main/java/com/google/protobuf/RopeByteString.java
+++ /dev/null
@@ -1,977 +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.InvalidObjectException;
-import java.io.ObjectInputStream;
-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 {
-    // Optimize for empty strings, but ensure we don't silently ignore invalid
-    // encodings.
-    return size() == 0 && UTF_8.equals(charsetName)
-        ? ""
-        : 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();
-    }
-  }
-
-  // =================================================================
-  // Serializable
-
-  private static final long serialVersionUID = 1L;
-
-  Object writeReplace() {
-    return new LiteralByteString(toByteArray());
-  }
-
-  private void readObject(ObjectInputStream in) throws IOException {
-    throw new InvalidObjectException(
-        "RopeByteStream instances are not to be serialized directly");
-  }
-
-  // =================================================================
-  // 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/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
deleted file mode 100644
index dd2b460..0000000
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ /dev/null
@@ -1,1998 +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)
-                  .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();
-    }
-
-    /** 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 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
-      } 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);
-      }
-
-      // For historical reasons, fields may optionally be separated by commas or
-      // semicolons.
-      if (!tokenizer.tryConsume(";")) {
-        tokenizer.tryConsume(",");
-      }
-    }
-
-    /**
-     * 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 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.
-
-  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.
-   */
-  public 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.
-   */
-  public 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.
-   */
-  public 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];
-      }
-    });
-  }
-
-  /**
-   * 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/UnknownFieldSetLite.java b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
deleted file mode 100644
index 7ea8402..0000000
--- a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
+++ /dev/null
@@ -1,297 +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;
-
-/**
- * {@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 {
-
-  private static final UnknownFieldSetLite DEFAULT_INSTANCE =
-      new UnknownFieldSetLite(ByteString.EMPTY);
-
-  /**
-   * Get an empty {@code UnknownFieldSetLite}.
-   *
-   * <p>For use by generated code only.
-   */
-  public static UnknownFieldSetLite getDefaultInstance() {
-    return DEFAULT_INSTANCE;
-  }
-
-  /**
-   * Create a new {@link Builder}.
-   *
-   * <p>For use by generated code only.
-   */
-  public static Builder newBuilder() {
-    return new Builder();
-  }
-
-  /**
-   * Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and
-   * {@code second}.
-   */
-  static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) {
-    return new UnknownFieldSetLite(first.byteString.concat(second.byteString));
-  }
-
-  /**
-   * The internal representation of the unknown fields.
-   */
-  private final ByteString byteString;
-
-  /**
-   * Constructs the {@code UnknownFieldSetLite} as a thin wrapper around {@link ByteString}.
-   */
-  private UnknownFieldSetLite(ByteString byteString) {
-    this.byteString = byteString;
-  }
-
-  /**
-   * Serializes the set and writes it to {@code output}.
-   *
-   * <p>For use by generated code only.
-   */
-  public void writeTo(CodedOutputStream output) throws IOException {
-    output.writeRawBytes(byteString);
-  }
-
-
-  /**
-   * Get the number of bytes required to encode this set.
-   *
-   * <p>For use by generated code only.
-   */
-  public int getSerializedSize() {
-    return byteString.size();
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (this == obj) {
-      return true;
-    }
-
-    if (obj instanceof UnknownFieldSetLite) {
-      return byteString.equals(((UnknownFieldSetLite) obj).byteString);
-    }
-
-    return false;
-  }
-
-  @Override
-  public int hashCode() {
-    return byteString.hashCode();
-  }
-
-  /**
-   * Builder for {@link UnknownFieldSetLite}s.
-   *
-   * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
-   *
-   * <p>For use by generated code only.
-   */
-  public static final class Builder {
-
-    private ByteString.Output byteStringOutput;
-    private CodedOutputStream output;
-    private boolean built;
-
-    /**
-     * Constructs a {@code Builder}. Lazily initialized by
-     * {@link #ensureInitializedButNotBuilt()}.
-     */
-    private Builder() {}
-
-    /**
-     * Ensures internal state is initialized for use.
-     */
-    private void ensureInitializedButNotBuilt() {
-      if (built) {
-        throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
-      }
-
-      if (output == null && byteStringOutput == null) {
-          byteStringOutput = ByteString.newOutput(100 /* initialCapacity */);
-          output = CodedOutputStream.newInstance(byteStringOutput);
-      }
-    }
-
-    /**
-     * 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.
-     */
-    public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
-                                  throws IOException {
-      ensureInitializedButNotBuilt();
-
-      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
-      switch (WireFormat.getTagWireType(tag)) {
-        case WireFormat.WIRETYPE_VARINT:
-          output.writeUInt64(fieldNumber, input.readInt64());
-          return true;
-        case WireFormat.WIRETYPE_FIXED32:
-          output.writeFixed32(fieldNumber, input.readFixed32());
-          return true;
-        case WireFormat.WIRETYPE_FIXED64:
-          output.writeFixed64(fieldNumber, input.readFixed64());
-          return true;
-        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-          output.writeBytes(fieldNumber, input.readBytes());
-          return true;
-        case WireFormat.WIRETYPE_START_GROUP:
-          final Builder subBuilder = newBuilder();
-          subBuilder.mergeFrom(input);
-          input.checkLastTagWas(
-              WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-
-          output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
-          subBuilder.build().writeTo(output);
-          output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
-          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.
-     */
-    public Builder mergeVarintField(int fieldNumber, int value) {
-      if (fieldNumber == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      ensureInitializedButNotBuilt();
-      try {
-        output.writeUInt64(fieldNumber, value);
-      } catch (IOException e) {
-        // Should never happen.
-      }
-      return this;
-    }
-
-    /**
-     * Convenience method for merging a length-delimited field.
-     *
-     * <p>For use by generated code only.
-     */
-    public Builder mergeLengthDelimitedField(
-        final int fieldNumber, final ByteString value) {  
-      if (fieldNumber == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      ensureInitializedButNotBuilt();
-      try {
-        output.writeBytes(fieldNumber, value);
-      } catch (IOException e) {
-        // Should never happen.
-      }
-      return this;
-    }
-
-    /**
-     * Build the {@link UnknownFieldSetLite} 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 IllegalStateException} to be
-     * thrown.
-     *
-     * <p>For use by generated code only.
-     */
-    public UnknownFieldSetLite build() {
-      if (built) {
-        throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
-      }
-
-      built = true;
-
-      final UnknownFieldSetLite result;
-      // If we were never initialized, no data was written.
-      if (output == null) {
-        result = getDefaultInstance();
-      } else {
-        try {
-          output.flush();
-        } catch (IOException e) {
-          // Should never happen.
-        }
-        ByteString byteString = byteStringOutput.toByteString();
-        if (byteString.isEmpty()) {
-          result = getDefaultInstance();
-        } else {
-          result = new UnknownFieldSetLite(byteString);
-        }
-      }
-
-      // Allow for garbage collection.
-      output = null;
-      byteStringOutput = null;
-      return result;
-    }
-
-    /**
-     * Parse an entire message from {@code input} and merge its fields into
-     * this set.
-     */
-    private Builder 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/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 ba83b66..0000000
--- a/java/src/main/java/com/google/protobuf/WireFormat.java
+++ /dev/null
@@ -1,245 +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;
-
-/**
- * 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);
-
-  /**
-   * 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 {
-      Object readString(CodedInputStream input) throws IOException {
-        return input.readString();
-      }
-    },
-    /** Eagerly parses to String; throws an IOException on invalid bytes. */
-    STRICT {
-      Object readString(CodedInputStream input) throws IOException {
-        return input.readStringRequireUtf8();
-      }
-    },
-    /** Keep data as ByteString; validation/conversion to String is lazy. */
-    LAZY {
-      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/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
deleted file mode 100644
index 6c9596c..0000000
--- a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
+++ /dev/null
@@ -1,87 +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.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";
-    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);
-  }
-
-  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/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/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/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
deleted file mode 100644
index 05832a1..0000000
--- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ /dev/null
@@ -1,741 +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 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/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/src/test/java/com/google/protobuf/FieldPresenceTest.java
deleted file mode 100644
index acf2b02..0000000
--- a/java/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ /dev/null
@@ -1,363 +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.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, new Class[]{}) != null) {
-        return true;
-      } else {
-        return false;
-      }
-    } catch (NoSuchMethodException e) {
-      return false;
-    }
-  }
-
-  private static boolean isHasMethodRemoved(
-      Class classWithFieldPresence,
-      Class classWithoutFieldPresence,
-      String camelName) {
-    return hasMethod(classWithFieldPresence, "get" + camelName)
-        && hasMethod(classWithFieldPresence, "has" + camelName)
-        && hasMethod(classWithoutFieldPresence, "get" + camelName)
-        && !hasMethod(classWithoutFieldPresence, "has" + camelName);
-  }
-
-  public void testHasMethod() {
-    // Optional non-message fields don't have a hasFoo() method generated.
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OptionalInt32"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OptionalString"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OptionalBytes"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OptionalNestedEnum"));
-
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OptionalInt32"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OptionalString"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OptionalBytes"));
-    assertTrue(isHasMethodRemoved(
-        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).
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OneofUint32"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OneofString"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OneofBytes"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OneofNestedMessage"));
-
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OneofUint32"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OneofString"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OneofBytes"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OneofNestedMessage"));
-  }
-
-  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/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
deleted file mode 100644
index 2bd8d1a..0000000
--- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ /dev/null
@@ -1,1662 +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.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 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);
-    }
-  }
-
-  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/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/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/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java
deleted file mode 100644
index 4d8037f..0000000
--- a/java/src/test/java/com/google/protobuf/LiteTest.java
+++ /dev/null
@@ -1,161 +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());
-  }
-  
-  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));
-  }
-}
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 046832d..0000000
--- a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ /dev/null
@@ -1,432 +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.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 {@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 testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException{
-    assertSame(classUnderTest + " must be the same string references",
-        ByteString.EMPTY.toString(UTF_8), new LiteralByteString(new byte[]{}).toString(UTF_8));
-  }
-
-  public void testToString_raisesException() throws UnsupportedEncodingException{
-    try {
-      ByteString.EMPTY.toString("invalid");
-      fail("Should have thrown an exception.");
-    } catch (UnsupportedEncodingException expected) {
-      // This is success
-    }
-
-    try {
-      new LiteralByteString(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",
-        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] = (byte) (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);
-  }
-
-  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/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
deleted file mode 100644
index 22dbeb7..0000000
--- a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ /dev/null
@@ -1,277 +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 map_lite_test.MapForProto2TestProto.TestMap;
-import map_lite_test.MapForProto2TestProto.TestMap.MessageValue;
-import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue;
-
-import junit.framework.TestCase;
-
-/**
- * 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 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 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 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());
-  }
-  
-}
diff --git a/java/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/src/test/java/com/google/protobuf/MapForProto2Test.java
deleted file mode 100644
index 78cba1b..0000000
--- a/java/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ /dev/null
@@ -1,516 +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 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.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 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 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 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());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/src/test/java/com/google/protobuf/MapTest.java
deleted file mode 100644
index b8e67b7..0000000
--- a/java/src/test/java/com/google/protobuf/MapTest.java
+++ /dev/null
@@ -1,614 +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 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.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 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 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 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());
-    }
-  }
-}
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 0f2344d..0000000
--- a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java
+++ /dev/null
@@ -1,161 +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.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 testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException {
-    RopeByteString ropeByteString =
-        RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
-    assertSame(classUnderTest + " must be the same string references",
-        ByteString.EMPTY.toString(UTF_8), ropeByteString.toString(UTF_8));
-  }
-
-  public void testToString_raisesException() throws UnsupportedEncodingException{
-    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
-    }
-  }
-
-  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/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 eba06ca..0000000
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ /dev/null
@@ -1,1005 +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").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) 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\\\\\\'\\\"\\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));
-
-    // 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() 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());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
deleted file mode 100644
index cec3da1..0000000
--- a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
+++ /dev/null
@@ -1,316 +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;
-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 testNoDataIsDefaultInstance() {
-    assertSame(
-        UnknownFieldSetLite.getDefaultInstance(),
-        UnknownFieldSetLite.newBuilder()
-            .build());
-  }
-
-  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.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeFieldFrom(input.readTag(), input);
-
-    assertEquals(foo.toByteString(), toByteString(builder.build()));
-  }
-
-  public void testSerializedSize() throws IOException {
-    Foo foo = Foo.newBuilder()
-      .setValue(2)
-      .build();
-
-    CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
-
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeFieldFrom(input.readTag(), input);
-
-    assertEquals(foo.toByteString().size(), builder.build().getSerializedSize());
-  }
-
-  public void testMergeVarintField() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
-
-    CodedInputStream input =
-        CodedInputStream.newInstance(toByteString(builder.build()).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 builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, -6);
-
-    CodedInputStream input =
-        CodedInputStream.newInstance(toByteString(builder.build()).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.Builder builder1 = UnknownFieldSetLite.newBuilder();
-    builder1.mergeVarintField(10, 2);
-    UnknownFieldSetLite unknownFields1 = builder1.build();
-
-    UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder();
-    builder2.mergeVarintField(10, 2);
-    UnknownFieldSetLite unknownFields2 = builder2.build();
-
-    assertEquals(unknownFields1, unknownFields2);
-    assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode());
-    assertFalse(unknownFields1.equals(UnknownFieldSetLite.getDefaultInstance()));
-    assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode());
-  }
-
-  public void testConcat() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
-    UnknownFieldSetLite unknownFields = builder.build();
-
-    unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields);
-
-    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 testConcat_empty() {
-    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat(
-        UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance());
-
-    assertEquals(0, unknownFields.getSerializedSize());
-    assertEquals(ByteString.EMPTY, toByteString(unknownFields));
-  }
-
-  public void testBuilderReuse() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
-    builder.build();
-
-    try {
-      builder.build();
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-
-    try {
-      builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-
-    try {
-      builder.mergeVarintField(5, 1);
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-  }
-
-  public void testBuilderReuse_empty() {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.build();
-
-    try {
-      builder.build();
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-  }
-
-  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("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.
-    }
-  }
-
-  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/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/field_presence_test.proto b/java/src/test/java/com/google/protobuf/field_presence_test.proto
deleted file mode 100644
index 8d8ea8e..0000000
--- a/java/src/test/java/com/google/protobuf/field_presence_test.proto
+++ /dev/null
@@ -1,93 +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.
-
-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 {
-    optional int32 value = 1;
-  }
-
-  optional int32 optional_int32 = 1;
-  optional string optional_string = 2;
-  optional bytes optional_bytes = 3;
-  optional NestedEnum optional_nested_enum = 4;
-  optional NestedMessage optional_nested_message = 5;
-  optional 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 {
-  optional int32 optional_int32 = 1;
-  optional string optional_string = 2;
-  optional bytes optional_bytes = 3;
-  optional TestAllTypes.NestedEnum optional_nested_enum = 4;
-  optional TestAllTypes.NestedMessage optional_nested_message = 5;
-  optional 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/src/test/java/com/google/protobuf/map_test.proto b/java/src/test/java/com/google/protobuf/map_test.proto
deleted file mode 100644
index bf692c2..0000000
--- a/java/src/test/java/com/google/protobuf/map_test.proto
+++ /dev/null
@@ -1,64 +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.
-
-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 {
-    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;
-}
-
-// 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 {
-  optional TestMap optional_message = 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 dc08261..0000000
--- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
+++ /dev/null
@@ -1,170 +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.
-
-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;
-  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;  // 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/util/pom.xml b/java/util/pom.xml
new file mode 100644
index 0000000..26c12c8
--- /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-2</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..dc2f4b8
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
@@ -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.
+
+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()) {
+            destination.setField(field, source.getField(field));
+          } else {
+            destination.getFieldBuilder(field).mergeFrom(
+                (Message) source.getField(field));
+          }
+        } else {
+          destination.setField(field, source.getField(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..0b3060a
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -0,0 +1,285 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 an union of two FieldMasks.
+   */
+  public static FieldMask union(FieldMask mask1, FieldMask mask2) {
+    return new FieldMaskTree(mask1).mergeFromFieldMask(mask2).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;
+
+    /**
+     * 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;
+    }
+    
+    public void setReplaceMessageFields(boolean value) {
+      replaceMessageFields = value;
+    }
+
+    public void setReplaceRepeatedFields(boolean value) {
+      replaceRepeatedFields = value;
+    }
+  }
+  
+  /**
+   * Merges fields specified by a FieldMask from one message to another.
+   */
+  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..d13ff0e
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -0,0 +1,1661 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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 Gson();
+    }
+
+    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 final String TYPE_URL_PREFIX = "type.googleapis.com";
+  
+  private static String getTypeName(String typeUrl)
+      throws InvalidProtocolBufferException {
+    String[] parts = typeUrl.split("/");
+    if (parts.length != 2 || !parts[0].equals(TYPE_URL_PREFIX)) {
+      throw new InvalidProtocolBufferException(
+          "Invalid type url found: " + typeUrl);
+    }
+    return parts[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 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 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);
+        FieldDescriptor listField =
+            listBuilder.getDescriptorForType().findFieldByName("values");
+        mergeRepeatedField(listField, 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..3391f23
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
@@ -0,0 +1,229 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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());
+    
+    // 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());
+  }
+}
+
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..a312fc3
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
@@ -0,0 +1,175 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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..c0eb033
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -0,0 +1,1156 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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);
+  }
+  
+  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 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..509c1d6
--- /dev/null
+++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.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 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;
+}
+
+message TestAny {
+  google.protobuf.Any any_value = 1;
+}
+
+message TestCustomJsonName {
+  int32 value = 1 [json_name = "@value"];
+}
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/README.txt b/javanano/README.txt
deleted file mode 100644
index cfb3c3b..0000000
--- a/javanano/README.txt
+++ /dev/null
@@ -1,356 +0,0 @@
-Protocol Buffers - Google's data interchange format
-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
-
-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.
-
-
-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
index 7a2be9d..2c9dd94 100644
--- a/javanano/pom.xml
+++ b/javanano/pom.xml
@@ -10,7 +10,7 @@
   </parent>
   <groupId>com.google.protobuf.nano</groupId>
   <artifactId>protobuf-javanano</artifactId>
-  <version>3.0.0-alpha-3-pre</version>
+  <version>3.0.0-alpha-5</version>
   <packaging>bundle</packaging>
   <name>Protocol Buffer JavaNano API</name>
   <description>
@@ -97,19 +97,19 @@
                   <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:target/generated-test-sources" />
+                  <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:target/generated-test-sources" />
+                  <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=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" />
+                  <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>
@@ -139,6 +139,15 @@
                   <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>
               </tasks>
               <testSourceRoot>target/generated-test-sources</testSourceRoot>
             </configuration>
@@ -156,7 +165,7 @@
           <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-3-pre</Export-Package>
+            <Export-Package>com.google.protobuf;version=3.0.0-alpha-5</Export-Package>
           </instructions>
         </configuration>
       </plugin>
@@ -165,6 +174,16 @@
   <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>
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
index b4f20fd..f399315 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
@@ -190,12 +190,12 @@
     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");
+      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), "UTF-8");
+      return new String(readRawBytes(size), InternalNano.UTF_8);
     }
   }
 
@@ -236,6 +236,8 @@
       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);
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
index 2777f34..322ada8 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -31,7 +31,10 @@
 package com.google.protobuf.nano;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ReadOnlyBufferException;
 
 /**
  * Encodes and writes protocol message fields.
@@ -48,15 +51,18 @@
  * @author kneton@google.com Kenton Varda
  */
 public final class CodedOutputByteBufferNano {
-  private final byte[] buffer;
-  private final int limit;
-  private int position;
+  /* 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;
-    position = offset;
-    limit = offset + length;
+    this.buffer.order(ByteOrder.LITTLE_ENDIAN);
   }
 
   /**
@@ -288,14 +294,213 @@
 
   /** 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);
+    // 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);
@@ -603,13 +808,8 @@
    * {@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.");
-    }
+    final int length = encodedLength(value);
+    return computeRawVarint32Size(length) + length;
   }
 
   /**
@@ -692,7 +892,7 @@
    * Otherwise, throws {@code UnsupportedOperationException}.
    */
   public int spaceLeft() {
-    return limit - position;
+    return buffer.remaining();
   }
 
   /**
@@ -710,6 +910,23 @@
   }
 
   /**
+   * 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.
@@ -725,12 +942,12 @@
 
   /** Write a single byte. */
   public void writeRawByte(final byte value) throws IOException {
-    if (position == limit) {
+    if (!buffer.hasRemaining()) {
       // We're writing to a single buffer.
-      throw new OutOfSpaceException(position, limit);
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
     }
 
-    buffer[position++] = value;
+    buffer.put(value);
   }
 
   /** Write a single byte, represented by an integer value. */
@@ -746,13 +963,11 @@
   /** 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;
+    if (buffer.remaining() >= length) {
+      buffer.put(value, offset, length);
     } else {
       // We're writing to a single buffer.
-      throw new OutOfSpaceException(position, limit);
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
     }
   }
 
@@ -825,24 +1040,20 @@
 
   /** 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);
+    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 {
-    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);
+    if (buffer.remaining() < 8) {
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
+    }
+    buffer.putLong(value);
   }
 
   public static final int LITTLE_ENDIAN_64_SIZE = 8;
diff --git a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
index b979390..87973d7 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -160,28 +160,10 @@
         return true;
     }
 
-    /**
-     * Returns whether the stored unknown field data in this message is equivalent to that in the
-     * other message.
-     *
-     * @param other the other message.
-     * @return whether the two sets of unknown field data are equal.
-     */
-    protected final boolean unknownFieldDataEquals(M other) {
-        if (unknownFieldData == null || unknownFieldData.isEmpty()) {
-            return other.unknownFieldData == null || other.unknownFieldData.isEmpty();
-        } else {
-            return unknownFieldData.equals(other.unknownFieldData);
-        }
-    }
-
-    /**
-     * Computes the hashcode representing the unknown field data stored in this message.
-     *
-     * @return the hashcode for the unknown field data.
-     */
-    protected final int unknownFieldDataHashCode() {
-        return (unknownFieldData == null || unknownFieldData.isEmpty()
-                ? 0 : unknownFieldData.hashCode());
+    @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
index c29b030..c458f9b 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/Extension.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
@@ -79,12 +79,30 @@
      * 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.
@@ -92,8 +110,8 @@
      * @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, int tag) {
-        return new Extension<M, T[]>(type, clazz, tag, true);
+            Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) {
+        return new Extension<M, T[]>(type, clazz, (int) tag, true);
     }
 
     /**
@@ -104,8 +122,8 @@
      * @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, int tag) {
-        return new PrimitiveExtension<M, T>(type, clazz, tag, false, 0, 0);
+            Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) {
+        return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0);
     }
 
     /**
@@ -117,8 +135,9 @@
      */
     public static <M extends ExtendableMessageNano<M>, T>
             Extension<M, T> createRepeatedPrimitiveTyped(
-                    int type, Class<T> clazz, int tag, int nonPackedTag, int packedTag) {
-        return new PrimitiveExtension<M, T>(type, clazz, tag, true, nonPackedTag, packedTag);
+                    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);
     }
 
     /**
@@ -136,7 +155,7 @@
     protected final Class<T> clazz;
 
     /**
-     * Tag number of this extension.
+     * Tag number of this extension. The data should be viewed as an unsigned 32-bit value.
      */
     public final int tag;
 
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
index cdb66da..b49a97f 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -32,12 +32,15 @@
 
 
 /**
- * A custom version of {@link android.util.SparseArray} with the minimal API
+ * A custom version of {@code android.util.SparseArray} with the minimal API
  * for storing {@link FieldData} objects.
  *
- * Based on {@link android.support.v4.util.SpareArrayCompat}.
+ * <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}.
  */
-class FieldArray {
+public final class FieldArray implements Cloneable {
     private static final FieldData DELETED = new FieldData();
     private boolean mGarbage = false;
 
@@ -48,7 +51,7 @@
     /**
      * Creates a new FieldArray containing no fields.
      */
-    public FieldArray() {
+    FieldArray() {
         this(10);
     }
 
@@ -57,7 +60,7 @@
      * require any additional memory allocation to store the specified
      * number of mappings.
      */
-    public FieldArray(int initialCapacity) {
+    FieldArray(int initialCapacity) {
         initialCapacity = idealIntArraySize(initialCapacity);
         mFieldNumbers = new int[initialCapacity];
         mData = new FieldData[initialCapacity];
@@ -68,7 +71,7 @@
      * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
      * if no such mapping has been made.
      */
-    public FieldData get(int fieldNumber) {
+    FieldData get(int fieldNumber) {
         int i = binarySearch(fieldNumber);
 
         if (i < 0 || mData[i] == DELETED) {
@@ -81,7 +84,7 @@
     /**
      * Removes the data from the specified fieldNumber, if there was any.
      */
-    public void remove(int fieldNumber) {
+    void remove(int fieldNumber) {
         int i = binarySearch(fieldNumber);
 
         if (i >= 0 && mData[i] != DELETED) {
@@ -118,7 +121,7 @@
      * Adds a mapping from the specified fieldNumber to the specified data,
      * replacing the previous mapping if there was one.
      */
-    public void put(int fieldNumber, FieldData data) {
+    void put(int fieldNumber, FieldData data) {
         int i = binarySearch(fieldNumber);
 
         if (i >= 0) {
@@ -167,7 +170,7 @@
      * Returns the number of key-value mappings that this FieldArray
      * currently stores.
      */
-    public int size() {
+    int size() {
         if (mGarbage) {
             gc();
         }
@@ -184,7 +187,7 @@
      * the value from the <code>index</code>th key-value mapping that this
      * FieldArray stores.
      */
-    public FieldData dataAt(int index) {
+    FieldData dataAt(int index) {
         if (mGarbage) {
             gc();
         }
@@ -270,4 +273,19 @@
         }
         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
index 21ead88..ebebabc 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
@@ -39,7 +39,7 @@
  * Stores unknown fields. These might be extensions or fields that the generated API doesn't
  * know about yet.
  */
-class FieldData {
+class FieldData implements Cloneable {
     private Extension<?, ?> cachedExtension;
     private Object value;
     /** The serialised values for this object. Will be cleared if getValue is called */
@@ -187,4 +187,54 @@
         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
index 4a08bb5..f1263df 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -33,7 +33,7 @@
 import com.google.protobuf.nano.MapFactories.MapFactory;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -67,6 +67,8 @@
   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() {}
 
@@ -111,14 +113,7 @@
    * 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);
-    }
+    return new String(bytes.getBytes(ISO_8859_1), InternalNano.UTF_8);
   }
 
   /**
@@ -130,14 +125,7 @@
    * 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);
-    }
+    return bytes.getBytes(ISO_8859_1);
   }
 
   /**
@@ -145,11 +133,7 @@
    * 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?");
-    }
+    return text.getBytes(InternalNano.UTF_8);
   }
 
   /**
@@ -552,4 +536,12 @@
     }
     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/MessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
index 81e5857..2347502 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -187,4 +187,12 @@
     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
index c4b2ad3..d9500bb 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
@@ -109,6 +109,10 @@
             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
diff --git a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
index a17fccf..b1678d1 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -42,6 +42,10 @@
 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) {
diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
index 4cc7722..debf7c0 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
+++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
@@ -31,17 +31,19 @@
 package com.google.protobuf.nano;
 
 import com.google.protobuf.nano.MapTestProto.TestMap;
+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.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 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;
 
@@ -458,7 +460,7 @@
     assertFalse(msg.optionalBytes.length > 0);
     msg.optionalBytes = InternalNano.copyFromUtf8("hello");
     assertTrue(msg.optionalBytes.length > 0);
-    assertEquals("hello", new String(msg.optionalBytes, "UTF-8"));
+    assertEquals("hello", new String(msg.optionalBytes, InternalNano.UTF_8));
     msg.clear();
     assertFalse(msg.optionalBytes.length > 0);
     msg.clear()
@@ -476,7 +478,7 @@
 
     TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
     assertTrue(newMsg.optionalBytes.length > 0);
-    assertEquals("bye", new String(newMsg.optionalBytes, "UTF-8"));
+    assertEquals("bye", new String(newMsg.optionalBytes, InternalNano.UTF_8));
   }
 
   public void testNanoOptionalGroup() throws Exception {
@@ -1346,14 +1348,14 @@
         InternalNano.copyFromUtf8("bye"),
         InternalNano.copyFromUtf8("boo")
     };
-    assertEquals("bye", new String(msg.repeatedBytes[1], "UTF-8"));
-    assertEquals("boo", new String(msg.repeatedBytes[2], "UTF-8"));
+    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], "UTF-8"));
+    assertEquals("boo", new String(msg.repeatedBytes[0], InternalNano.UTF_8));
     msg.clear();
     assertEquals(0, msg.repeatedBytes.length);
 
@@ -1385,8 +1387,8 @@
 
     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"));
+    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 {
@@ -2277,9 +2279,9 @@
       assertTrue(52.0e3 == msg.defaultDouble);
       assertEquals(true, msg.defaultBool);
       assertEquals("hello", msg.defaultString);
-      assertEquals("world", new String(msg.defaultBytes, "UTF-8"));
+      assertEquals("world", new String(msg.defaultBytes, InternalNano.UTF_8));
       assertEquals("dünya", msg.defaultStringNonascii);
-      assertEquals("dünyab", new String(msg.defaultBytesNonascii, "UTF-8"));
+      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);
@@ -2300,6 +2302,59 @@
     }
   }
 
+  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.
@@ -2385,7 +2440,7 @@
     assertEquals(TestAllTypesNanoHas.FOO, newMsg.optionalNestedEnum);
     assertEquals(41, newMsg.defaultInt32);
     assertEquals("hello", newMsg.defaultString);
-    assertEquals("world", new String(newMsg.defaultBytes, "UTF-8"));
+    assertEquals("world", new String(newMsg.defaultBytes, InternalNano.UTF_8));
     assertEquals(TestAllTypesNanoHas.BAR, newMsg.defaultNestedEnum);
     assertEquals(Float.NaN, newMsg.defaultFloatNan);
     assertEquals(0, newMsg.id);
@@ -2567,7 +2622,7 @@
     assertEquals(TestNanoAccessors.FOO, newMsg.getOptionalNestedEnum());
     assertEquals(41, newMsg.getDefaultInt32());
     assertEquals("hello", newMsg.getDefaultString());
-    assertEquals("world", new String(newMsg.getDefaultBytes(), "UTF-8"));
+    assertEquals("world", new String(newMsg.getDefaultBytes(), InternalNano.UTF_8));
     assertEquals(TestNanoAccessors.BAR, newMsg.getDefaultNestedEnum());
     assertEquals(Float.NaN, newMsg.getDefaultFloatNan());
     assertEquals(0, newMsg.id);
@@ -2986,6 +3041,10 @@
     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 {
@@ -4345,6 +4404,11 @@
     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.
@@ -4364,6 +4428,22 @@
     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));
+  }
+
   private void assertHasWireData(MessageNano message, boolean expected) {
     byte[] bytes = MessageNano.toByteArray(message);
     int wireLength = bytes.length;
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
index f72833a..51498a4 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
+++ b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
@@ -32,7 +32,7 @@
 
 package map_test;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "MapTestProto";
 
 message TestMap {
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
index 6e5a40f..6511e47 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "NanoAccessorsOuterClass";
 
 message TestNanoAccessors {
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
index e6246bb..958e1f1 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_multiple_files = true;
 
 enum FileScopeEnumMultiple {
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
index 33a8622..3a1e07f 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "EnumClassNanos";
 
 enum FileScopeEnum {
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
index f7f5742..c0da8b4 100644
--- 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
@@ -1,6 +1,6 @@
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "EnumValidity";
 
 enum E {
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
index 2a678a8..ca56b3d 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
@@ -16,11 +16,15 @@
 message AnotherMessage {
   optional string string = 1;
   optional bool value = 2;
+  repeated int32 integers = 3;
 }
 
 message ContainerMessage {
   extend ExtendableMessage {
     optional bool another_thing = 100;
+    // The largest permitted field number, per
+    // https://developers.google.com/protocol-buffers/docs/proto#simple
+    optional bool large_field_number = 536870911;
   }
 }
 
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
index 7d47682..3b7a004 100644
--- 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
@@ -1,7 +1,7 @@
 syntax = "proto2";
 
 option java_multiple_files = true;
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 
 import "google/protobuf/nano/unittest_extension_nano.proto";
 
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
index 6d4b5df..e533c65 100644
--- 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
@@ -1,7 +1,7 @@
 syntax = "proto2";
 
 option java_multiple_files = true;
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 
 import "google/protobuf/nano/unittest_extension_nano.proto";
 
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
index 589754e..8b2d965 100644
--- 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
@@ -1,7 +1,7 @@
 syntax = "proto2";
 
 option java_multiple_files = true;
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 
 import "google/protobuf/nano/unittest_extension_nano.proto";
 
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
index bda1a6e..fe7d179 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "NanoHasOuterClass";
 
 message TestAllTypesNanoHas {
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
index 9db2d3e..b31c439 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest_import;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "MultipleNameClashNano";
 option java_multiple_files = true;
 
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
index 9dbf0de..406ab77 100644
--- 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
@@ -34,7 +34,7 @@
 
 import "google/protobuf/nano/unittest_import_nano.proto";
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_multiple_files = true;
 
 enum FileScopeEnum {
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
index efaf526..3fff24c 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
@@ -34,7 +34,7 @@
 
 import "google/protobuf/nano/unittest_import_nano.proto";
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "NanoOuterClass";
 
 // Same as TestAllTypes but with the nano runtime.
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
index 69d0583..29b944f 100644
--- 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
@@ -33,7 +33,7 @@
 
 package protobuf_unittest_import;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 // Explicit outer classname to suppress legacy info.
 option java_outer_classname = "UnittestRecursiveNano";
 
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
index 2b24615..82eb8d1 100644
--- 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
@@ -1,6 +1,6 @@
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "NanoReferenceTypes";
 
 message TestAllTypesNano {
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
index 9bfc3ad..ef4e2d2 100644
--- 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
@@ -34,7 +34,7 @@
 
 import "google/protobuf/nano/unittest_nano.proto";
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_multiple_files = true;
 
 // A container message for testing the merging of repeated fields at a
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
index a7ca752..96af885 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 option java_outer_classname = "NanoRepeatedPackables";
 
 enum Enum {
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
index 48333ab..25786cc 100644
--- 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
@@ -33,7 +33,7 @@
 
 package protobuf_unittest_import;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 // Explicit outer classname to suppress legacy info.
 option java_outer_classname = "UnittestSimpleNano";
 
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
index 025428d..7de30c8 100644
--- 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
@@ -32,7 +32,7 @@
 
 package protobuf_unittest_import;
 
-option java_package = "com.google.protobuf.nano";
+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
index 21bd8c0..bbd677c 100644
--- 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
@@ -33,7 +33,7 @@
 
 package protobuf_unittest_import;
 
-option java_package = "com.google.protobuf.nano";
+option java_package = "com.google.protobuf";
 // Explicit outer classname to suppress legacy info.
 option java_outer_classname = "UnittestStringutf8Nano";
 
diff --git a/js/README.md b/js/README.md
new file mode 100644
index 0000000..fc144a3
--- /dev/null
+++ b/js/README.md
@@ -0,0 +1,14 @@
+This directory contains Protocol Buffer support for JavaScript.  This code works
+in browsers and in Node.js.
+
+The packaging work for this is still in-progress.  For now you can just run the
+tests.  First you need to build the main C++ distribution because the code
+generator for JavaScript is written in C++:
+
+   $ ./autogen.sh
+   $ ./configure
+   $ make
+
+Then you can run the JavaScript tests in this directory:
+
+   $ cd js && gulp test
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..a976e0b
--- /dev/null
+++ b/js/binary/constants.js
@@ -0,0 +1,320 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.ConstBinaryMessage');
+goog.provide('jspb.ReaderFunction');
+goog.provide('jspb.RecyclerFunction');
+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 field in jspb can be a scalar, a block of bytes, another proto, or an
+ * array of any of the above.
+ * @typedef {boolean|number|string|Uint8Array|
+             jspb.BinaryMessage|jsproto.BinaryExtension|
+             Array<jspb.AnyFieldType>}
+ */
+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;
+
+
+/**
+ * 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..9004eff
--- /dev/null
+++ b/js/binary/decoder.js
@@ -0,0 +1,1005 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 null if the length was
+ *     invalid.
+ */
+jspb.BinaryDecoder.prototype.readBytes = function(length) {
+  if (length < 0 ||
+      this.cursor_ + length > this.bytes_.length) {
+    this.error_ = true;
+    return null;
+  }
+
+  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..27342e4
--- /dev/null
+++ b/js/binary/decoder_test.js
@@ -0,0 +1,327 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.BinaryWriter');
+
+
+/**
+ * Tests raw 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 writer = new jspb.BinaryWriter();
+
+  // Encode zero and limits.
+  writeValue.call(writer, filter(0));
+  writeValue.call(writer, filter(epsilon));
+  writeValue.call(writer, filter(upperLimit));
+
+  // Encode positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    writeValue.call(writer, filter(cursor));
+  }
+
+  var reader = jspb.BinaryDecoder.alloc(writer.getResultBuffer());
+
+  // Check zero and limits.
+  assertEquals(filter(0), readValue.call(reader));
+  assertEquals(filter(epsilon), readValue.call(reader));
+  assertEquals(filter(upperLimit), readValue.call(reader));
+
+  // Check positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    if (filter(cursor) != readValue.call(reader)) throw 'fail!';
+  }
+}
+
+
+/**
+ * Tests raw 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 writer = new jspb.BinaryWriter();
+
+  // Encode zero and limits.
+  writeValue.call(writer, filter(lowerLimit));
+  writeValue.call(writer, filter(-epsilon));
+  writeValue.call(writer, filter(0));
+  writeValue.call(writer, filter(epsilon));
+  writeValue.call(writer, filter(upperLimit));
+
+  var inputValues = [];
+
+  // Encode negative values.
+  for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
+    var val = filter(cursor);
+    writeValue.call(writer, val);
+    inputValues.push(val);
+  }
+
+  // Encode positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    var val = filter(cursor);
+    writeValue.call(writer, val);
+    inputValues.push(val);
+  }
+
+  var reader = jspb.BinaryDecoder.alloc(writer.getResultBuffer());
+
+  // Check zero and limits.
+  assertEquals(filter(lowerLimit), readValue.call(reader));
+  assertEquals(filter(-epsilon), readValue.call(reader));
+  assertEquals(filter(0), readValue.call(reader));
+  assertEquals(filter(epsilon), readValue.call(reader));
+  assertEquals(filter(upperLimit), readValue.call(reader));
+
+  // Verify decoded values.
+  for (var i = 0; i < inputValues.length; i++) {
+    assertEquals(inputValues[i], readValue.call(reader));
+  }
+}
+
+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 writer = new jspb.BinaryWriter();
+
+    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);
+
+    writer.rawWriteVarintHash64(hashA);
+    writer.rawWriteVarintHash64(hashB);
+    writer.rawWriteVarintHash64(hashC);
+    writer.rawWriteVarintHash64(hashD);
+
+    writer.rawWriteFixedHash64(hashA);
+    writer.rawWriteFixedHash64(hashB);
+    writer.rawWriteFixedHash64(hashC);
+    writer.rawWriteFixedHash64(hashD);
+
+    var decoder = jspb.BinaryDecoder.alloc(writer.getResultBuffer());
+
+    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 raw encoding and decoding of unsigned integers.
+   */
+  it('testRawUnsigned', function() {
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint8,
+        jspb.BinaryWriter.prototype.rawWriteUint8,
+        1, 0xFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint16,
+        jspb.BinaryWriter.prototype.rawWriteUint16,
+        1, 0xFFFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint32,
+        jspb.BinaryWriter.prototype.rawWriteUint32,
+        1, 0xFFFFFFFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint64,
+        jspb.BinaryWriter.prototype.rawWriteUint64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+  });
+
+
+  /**
+   * Tests raw encoding and decoding of signed integers.
+   */
+  it('testRawSigned', function() {
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt8,
+        jspb.BinaryWriter.prototype.rawWriteInt8,
+        1, -0x80, 0x7F, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt16,
+        jspb.BinaryWriter.prototype.rawWriteInt16,
+        1, -0x8000, 0x7FFF, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt32,
+        jspb.BinaryWriter.prototype.rawWriteInt32,
+        1, -0x80000000, 0x7FFFFFFF, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt64,
+        jspb.BinaryWriter.prototype.rawWriteInt64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests raw encoding and decoding of floats.
+   */
+  it('testRawFloats', 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.BinaryWriter.prototype.rawWriteFloat,
+        jspb.BinaryConstants.FLOAT32_EPS,
+        -jspb.BinaryConstants.FLOAT32_MAX,
+        jspb.BinaryConstants.FLOAT32_MAX,
+        truncate);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readDouble,
+        jspb.BinaryWriter.prototype.rawWriteDouble,
+        jspb.BinaryConstants.FLOAT64_EPS * 10,
+        -jspb.BinaryConstants.FLOAT64_MAX,
+        jspb.BinaryConstants.FLOAT64_MAX,
+        function(x) { return x; });
+  });
+});
diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js
new file mode 100644
index 0000000..1cb7ff0
--- /dev/null
+++ b/js/binary/proto_test.js
@@ -0,0 +1,487 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.testing.asserts');
+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');
+
+var suite = {};
+
+/**
+ * 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']);
+  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 a string with codepoints 0--255.
+ * @param {Uint8Array|string} arr
+ * @param {string} str
+ * @return {boolean}
+ */
+function bytesCompare(arr, str) {
+  if (arr.length != str.length) {
+    return false;
+  }
+  if (typeof arr == 'string') {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr.charCodeAt(i) != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  } else {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr[i] != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+
+/**
+ * Helper: verify contents of given TestAllTypes message as set by
+ * fillAllFields().
+ * @param {proto.jspb.test.TestAllTypes} msg
+ */
+function checkAllFields(msg) {
+  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.getOptionalGroup().getA(), 100);
+  assertEquals(msg.getOptionalForeignMessage().getC(), 16);
+  assertEquals(msg.getOptionalForeignEnum(),
+      proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+  assertEquals(msg.getOneofString(), 'oneof');
+  assertEquals(msg.getOneofFieldCase(),
+      proto.jspb.test.TestAllTypes.OneofFieldCase.ONEOF_STRING);
+
+  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.getRepeatedGroupList().length, 1);
+  assertEquals(msg.getRepeatedGroupList()[0].getA(), 100);
+  assertEquals(msg.getRepeatedForeignMessageList().length, 1);
+  assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000);
+  assertElementsEquals(msg.getRepeatedForeignEnumList(),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  assertElementsEquals(msg.getPackedRepeatedInt32List(), [-42]);
+  assertElementsEquals(msg.getPackedRepeatedInt64List(),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(msg.getPackedRepeatedUint32List(), [0x80000000]);
+  assertElementsEquals(msg.getPackedRepeatedUint64List(), [0xf000000000000000]);
+  assertElementsEquals(msg.getPackedRepeatedSint32List(), [-100]);
+  assertElementsEquals(msg.getPackedRepeatedSint64List(),
+      [-0x8000000000000000]);
+  assertElementsEquals(msg.getPackedRepeatedFixed32List(), [1234]);
+  assertElementsEquals(msg.getPackedRepeatedFixed64List(),
+      [0x1234567800000000]);
+  assertElementsEquals(msg.getPackedRepeatedSfixed32List(), [-1234]);
+  assertElementsEquals(msg.getPackedRepeatedSfixed64List(),
+      [-0x1234567800000000]);
+  assertElementsEquals(msg.getPackedRepeatedFloatList(), [1.5]);
+  assertElementsEquals(msg.getPackedRepeatedDoubleList(), [-1.5]);
+  assertElementsEquals(msg.getPackedRepeatedBoolList(), [true]);
+}
+
+
+/**
+ * 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());
+  assertEquals(proto.jspb.test.ForeignEnum.FOREIGN_FOO,
+      msg.getExtension(proto.jspb.test.extendOptionalForeignEnum));
+
+  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(decoded);
+  });
+
+
+  /**
+   * 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..abcd166
--- /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..a648261
--- /dev/null
+++ b/js/binary/reader_test.js
@@ -0,0 +1,889 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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. We use the internal
+    // .rawWriteVarint() to ensure the tested wire data is what we want,
+    // independently of any serialization logic.
+    writer.writeInt32(5, sentinel);
+    // Start group, field 5.
+    writer.rawWriteVarint(
+        (5 << 3) + jspb.BinaryConstants.WireType.START_GROUP);
+    // Varint, field 42.
+    writer.rawWriteVarint(
+        (42 << 3) + jspb.BinaryConstants.WireType.VARINT);
+    // Varint data.
+    writer.rawWriteVarint(42);
+    // Start group, field 6.
+    writer.rawWriteVarint(
+        (6 << 3) + jspb.BinaryConstants.WireType.START_GROUP);
+    // Varint, field 84.
+    writer.rawWriteVarint(
+        (84 << 3) + jspb.BinaryConstants.WireType.VARINT);
+    writer.rawWriteVarint(42);
+    // End group, field 6.
+    writer.rawWriteVarint(
+        (6 << 3) + jspb.BinaryConstants.WireType.END_GROUP);
+    // End group, field 5.
+    writer.rawWriteVarint(
+        (5 << 3) + jspb.BinaryConstants.WireType.END_GROUP);
+
+    // 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..9260038
--- /dev/null
+++ b/js/binary/utils.js
@@ -0,0 +1,979 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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;
+};
+
+
+/**
+ * Clones a scalar field. Pulling this out to a helper method saves us a few
+ * bytes of generated code.
+ * @param {Array} array
+ * @return {Array}
+ */
+jspb.utils.cloneRepeatedScalarField = function(array) {
+  return array ? array.slice() : null;
+};
+
+
+/**
+ * Clones an array of messages using the provided cloner function.
+ * @param {Array.<jspb.BinaryMessage>} messages
+ * @param {jspb.ClonerFunction} cloner
+ * @return {Array.<jspb.BinaryMessage>}
+ */
+jspb.utils.cloneRepeatedMessageField = function(messages, cloner) {
+  if (messages === null) return null;
+  var result = [];
+  for (var i = 0; i < messages.length; i++) {
+    result.push(cloner(messages[i]));
+  }
+  return result;
+};
+
+
+/**
+ * Clones an array of byte blobs.
+ * @param {Array.<Uint8Array>} blobs
+ * @return {Array.<Uint8Array>}
+ */
+jspb.utils.cloneRepeatedBlobField = function(blobs) {
+  if (blobs === null) return null;
+  var result = [];
+  for (var i = 0; i < blobs.length; i++) {
+    result.push(new Uint8Array(blobs[i]));
+  }
+  return result;
+};
+
+
+/**
+ * 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.
+ * @param {boolean=} opt_stringIsRawBytes The string is interpreted as a series
+ * of raw bytes rather than base64 data.
+ * @return {string} Stringified bytes for text format.
+ */
+jspb.utils.debugBytesToTextFormat = function(byteSource,
+                                                opt_stringIsRawBytes) {
+  var s = '"';
+  if (byteSource) {
+    var bytes =
+        jspb.utils.byteSourceToUint8Array(byteSource, opt_stringIsRawBytes);
+    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}
+ * @private
+ */
+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
+ * @param {boolean=} opt_stringIsRawBytes Interpret a string as a series of raw
+ * bytes (encoded as codepoints 0--255 inclusive) rather than base64 data
+ * (default behavior).
+ * @return {!Uint8Array}
+ * @suppress {invalidCasts}
+ */
+jspb.utils.byteSourceToUint8Array = function(data, opt_stringIsRawBytes) {
+  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);
+    if (opt_stringIsRawBytes) {
+      return jspb.utils.stringToByteArray_(data);
+    } else {
+      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..5c33079
--- /dev/null
+++ b/js/binary/utils_test.js
@@ -0,0 +1,632 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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 writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.rawWriteVarint(Math.floor(i));
+      count++;
+    }
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count, 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));
+
+    // Converting binary-data strings into Uint8Arrays should work.
+    check(convert(sourceString, /* opt_stringIsRawBytes = */ true));
+  });
+});
diff --git a/js/binary/writer.js b/js/binary/writer.js
new file mode 100644
index 0000000..a184945
--- /dev/null
+++ b/js/binary/writer.js
@@ -0,0 +1,2124 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.arith.Int64');
+goog.require('jspb.arith.UInt64');
+goog.require('jspb.utils');
+
+goog.forwardDeclare('jspb.Message');
+
+
+
+/**
+ * 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 the temp
+   * buffer.
+   * @private {number}
+   */
+  this.totalLength_ = 0;
+
+  /**
+   * Temporary buffer holding 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 temp buffer will be added to the
+   * block array above and a new temp buffer will be created.
+   * @private {!Array.<number>}
+   */
+  this.temp_ = [];
+
+  /**
+   * 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.<!jspb.BinaryWriter.Bookmark_>}
+   */
+  this.bookmarks_ = [];
+};
+
+
+/**
+ * @typedef {{block: !Array.<number>, length: number}}
+ * @private
+ */
+jspb.BinaryWriter.Bookmark_;
+
+
+/**
+ * Saves the current temp buffer in the blocks_ array and starts a new one.
+ * @return {!Array.<number>} Returns a reference to the old temp buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.saveTempBuffer_ = function() {
+  var oldTemp = this.temp_;
+  this.blocks_.push(this.temp_);
+  this.totalLength_ += this.temp_.length;
+  this.temp_ = [];
+  return oldTemp;
+};
+
+
+/**
+ * Append a typed array of bytes onto the buffer.
+ *
+ * @param {!Uint8Array} arr The byte array to append.
+ * @private
+ */
+jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
+  if (this.temp_.length) {
+    this.saveTempBuffer_();
+  }
+  this.blocks_.push(arr);
+  this.totalLength_ += arr.length;
+};
+
+
+/**
+ * Append an untyped array of bytes onto the buffer.
+ *
+ * @param {!Array.<number>} arr The byte array to append.
+ * @private
+ */
+jspb.BinaryWriter.prototype.appendArray_ = function(arr) {
+  if (this.temp_.length) {
+    this.saveTempBuffer_();
+  }
+  this.temp_ = arr;
+};
+
+
+/**
+ * Begins a length-delimited section by writing the field header to the current
+ * temp buffer and then saving it in the block array. Returns the saved block,
+ * which we will append the length to in endDelimited_ below.
+ * @param {number} field
+ * @return {!jspb.BinaryWriter.Bookmark_}
+ * @private
+ */
+jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  return {block: this.saveTempBuffer_(), length: this.totalLength_};
+};
+
+
+/**
+ * Ends a length-delimited block 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. Note that 'parentLength' _must_ be the
+ * total length _after_ the field header was written in beginDelimited_ above.
+ * @param {!jspb.BinaryWriter.Bookmark_} bookmark
+ * @private
+ */
+jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
+  var messageLength = this.totalLength_ + this.temp_.length - bookmark.length;
+  goog.asserts.assert(messageLength >= 0);
+
+  var bytes = 1;
+  while (messageLength > 127) {
+    bookmark.block.push((messageLength & 0x7f) | 0x80);
+    messageLength = messageLength >>> 7;
+    bytes++;
+  }
+
+  bookmark.block.push(messageLength);
+  this.totalLength_ += bytes;
+};
+
+
+/**
+ * Resets the writer, throwing away any accumulated buffers.
+ */
+jspb.BinaryWriter.prototype.reset = function() {
+  this.blocks_ = [];
+  this.temp_ = [];
+  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.temp_.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;
+  }
+
+  flat.set(this.temp_, offset);
+  offset += this.temp_.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];
+  this.temp_ = [];
+
+  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 32-bit unsigned integer into its wire-format varint representation
+ * and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteUnsignedVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+
+  while (value > 127) {
+    this.temp_.push((value & 0x7f) | 0x80);
+    value = value >>> 7;
+  }
+
+  this.temp_.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.BinaryWriter.prototype.rawWriteSignedVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  if (value >= 0) {
+    this.rawWriteUnsignedVarint32(value);
+    return;
+  }
+
+  // Write nine bytes with a _signed_ right shift so we preserve the sign bit.
+  for (var i = 0; i < 9; i++) {
+    this.temp_.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.temp_.push(1);
+};
+
+
+/**
+ * Encodes an unsigned 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.BinaryWriter.prototype.rawWriteSplitVarint =
+    function(lowBits, highBits) {
+  // 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.temp_.push((lowBits & 0x7f) | 0x80);
+    lowBits = ((lowBits >>> 7) | (highBits << 25)) >>> 0;
+    highBits = highBits >>> 7;
+  }
+  this.temp_.push(lowBits);
+};
+
+
+/**
+ * Encodes a JavaScript integer into its wire-format varint representation and
+ * stores it in the buffer. Due to the way the varint encoding works this
+ * behaves correctly for both signed and unsigned integers, though integers
+ * that are not representable in 64 bits will still be truncated.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteVarint = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  jspb.utils.splitInt64(value);
+  this.rawWriteSplitVarint(jspb.utils.split64Low,
+                           jspb.utils.split64High);
+};
+
+
+/**
+ * Encodes a jspb.arith.{Int64,UInt64} instance into its wire-format
+ * varint representation and stores it in the buffer. Due to the way the varint
+ * encoding works this behaves correctly for both signed and unsigned integers,
+ * though integers that are not representable in 64 bits will still be
+ * truncated.
+ * @param {jspb.arith.Int64|jspb.arith.UInt64} value
+ */
+jspb.BinaryWriter.prototype.rawWriteVarintFromNum = function(value) {
+  this.rawWriteSplitVarint(value.lo, value.hi);
+};
+
+
+/**
+ * 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.BinaryWriter.prototype.rawWriteZigzagVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  this.rawWriteUnsignedVarint32(((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.BinaryWriter.prototype.rawWriteZigzagVarint = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  jspb.utils.splitZigzag64(value);
+  this.rawWriteSplitVarint(jspb.utils.split64Low,
+                           jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteUint8 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) && (value < 256));
+  this.temp_.push((value >>> 0) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteUint16 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) && (value < 65536));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteUint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+  this.temp_.push((value >>> 16) & 0xFF);
+  this.temp_.push((value >>> 24) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteUint64 = 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.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteInt8 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -128) && (value < 128));
+  this.temp_.push((value >>> 0) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteInt16 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -32768) && (value < 32768));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteInt32 = 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.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+  this.temp_.push((value >>> 16) & 0xFF);
+  this.temp_.push((value >>> 24) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteInt64 = 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.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteFloat = function(value) {
+  jspb.utils.splitFloat32(value);
+  this.rawWriteUint32(jspb.utils.split64Low);
+};
+
+
+/**
+ * Writes a raw 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.BinaryWriter.prototype.rawWriteDouble = function(value) {
+  jspb.utils.splitFloat64(value);
+  this.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw boolean value to the buffer as a varint.
+ * @param {boolean} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteBool = function(value) {
+  goog.asserts.assert(goog.isBoolean(value));
+  this.temp_.push(~~value);
+};
+
+
+/**
+ * Writes an raw enum value to the buffer as a varint.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteEnum = 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.rawWriteSignedVarint32(value);
+};
+
+
+/**
+ * Writes a raw string value to the buffer.
+ * @param {string} string The string to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteUtf8String = function(string) {
+  for (var i = 0; i < string.length; i++) {
+    this.temp_.push(string.charCodeAt(i));
+  }
+};
+
+
+/**
+ * Writes an arbitrary raw byte array to the buffer.
+ * @param {!Uint8Array} bytes The array of bytes to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteBytes = function(bytes) {
+  this.appendUint8Array_(bytes);
+};
+
+
+/**
+ * Writes an arbitrary raw byte array 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.rawWriteByteRange = function(bytes, start, end) {
+  this.appendUint8Array_(bytes.subarray(start, end));
+};
+
+
+/**
+ * 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.BinaryWriter.prototype.rawWriteVarintHash64 = function(hash) {
+  jspb.utils.splitHash64(hash);
+  this.rawWriteSplitVarint(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.BinaryWriter.prototype.rawWriteFixedHash64 = function(hash) {
+  jspb.utils.splitHash64(hash);
+  this.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * 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.rawWriteFieldHeader_ =
+    function(field, wireType) {
+  goog.asserts.assert(field >= 1 && field == Math.floor(field));
+  var x = field * 8 + wireType;
+  this.rawWriteUnsignedVarint32(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteSignedVarint32(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteSignedVarint32(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.writeVarint_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarint(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteZigzagVarint32(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.writeZigzagVarint_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteZigzagVarint(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.writeVarint_(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarintFromNum(num);
+};
+
+
+/**
+ * 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.writeVarint_(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarintFromNum(num);
+};
+
+
+/**
+ * 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.writeZigzagVarint_(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.rawWriteUint32(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteUint64(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.rawWriteInt32(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteInt64(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.rawWriteFloat(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteDouble(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.temp_.push(~~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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteSignedVarint32(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;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+
+  // Conversion loop swiped from goog.crypt.stringToUtf8ByteArray. Note that
+  // 'bytes' will be at least as long as 'value', but could be longer if we
+  // need to unpack unicode characters.
+  var bytes = [];
+  for (var i = 0; i < value.length; i++) {
+    var c = value.charCodeAt(i);
+    if (c < 128) {
+      bytes.push(c);
+    } else if (c < 2048) {
+      bytes.push((c >> 6) | 192);
+      bytes.push((c & 63) | 128);
+    } else {
+      bytes.push((c >> 12) | 224);
+      bytes.push(((c >> 6) & 63) | 128);
+      bytes.push((c & 63) | 128);
+    }
+  }
+
+  this.rawWriteUnsignedVarint32(bytes.length);
+  this.appendArray_(bytes);
+};
+
+
+/**
+ * Writes an arbitrary byte field to the buffer. Note - to match the behavior
+ * of the C++ implementation, empty byte arrays _are_ serialized.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {jspb.ByteSource} value The array of bytes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @param {boolean=} opt_stringIsRawBytes If `value` is a string, interpret it
+ * as a series of raw bytes (codepoints 0--255 inclusive) rather than base64
+ * data.
+ */
+jspb.BinaryWriter.prototype.writeBytes =
+    function(field, value, opt_buffer, opt_start, opt_end,
+             opt_stringIsRawBytes) {
+  if (value != null) {
+    this.rawWriteFieldHeader_(field,
+        jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length);
+    this.rawWriteBytes(
+        jspb.utils.byteSourceToUint8Array(value, opt_stringIsRawBytes));
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an arbitrary byte field to the buffer, with `opt_stringIsRawBytes`
+ * flag implicitly true.
+ * @param {number} field
+ * @param {jspb.ByteSource} value The array of bytes to write.
+ */
+jspb.BinaryWriter.prototype.writeBytesRawString = function(field, value) {
+  this.writeBytes(field, value, null, null, null, true);
+};
+
+
+/**
+ * Writes a message to the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @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.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writeMessage =
+    function(field, value, writerCallback, opt_buffer, opt_start, opt_end) {
+  if (value !== null) {
+    var bookmark = this.beginDelimited_(field);
+
+    writerCallback(value, this);
+
+    this.endDelimited_(bookmark);
+  } else if (opt_buffer && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * 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) {
+    this.rawWriteFieldHeader_(
+        field, jspb.BinaryConstants.WireType.START_GROUP);
+    writerCallback(value, this);
+    this.rawWriteFieldHeader_(
+        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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteFixedHash64(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.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarintHash64(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.writeRepeatedVarint_ = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeVarint_(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.writeZigzagVarint_(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.writeRepeatedVarint_;
+
+
+/**
+ * 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.writeRepeatedVarint_;
+
+
+/**
+ * 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.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<!Uint8Array|string>} value
+ *     The arrays of arrays of bytes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @param {boolean=} opt_stringIsRawBytes Any values that are strings are
+ * interpreted as raw bytes rather than base64 data.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBytes =
+    function(field, value, opt_buffer, opt_start, opt_end,
+             opt_stringIsRawBytes) {
+  if (value != null) {
+    for (var i = 0; i < value.length; i++) {
+      this.writeBytes(field, value[i], null, null, null, opt_stringIsRawBytes);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of arbitrary byte fields to the buffer, with
+ * `opt_stringIsRawBytes` implicitly true.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBytesRawString =
+    function(field, value) {
+  this.writeRepeatedBytes(field, value, null, null, null, true);
+};
+
+
+/**
+ * Writes an array of messages to the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @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.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedMessage =
+    function(field, value, writerCallback, opt_buffer, opt_start, opt_end) {
+  if (value) {
+    for (var i = 0; i < value.length; i++) {
+      var bookmark = this.beginDelimited_(field);
+
+      writerCallback(value[i], this);
+
+      this.endDelimited_(bookmark);
+    }
+  } else if (opt_buffer && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * 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) {
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteFieldHeader_(
+          field, jspb.BinaryConstants.WireType.START_GROUP);
+      writerCallback(value[i], this);
+      this.rawWriteFieldHeader_(
+          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.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteUnsignedVarint32(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedSignedVarint32_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteSignedVarint32(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedVarint_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteVarint(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed zigzag field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedZigzag_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteZigzagVarint(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed 32-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+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.rawWriteSignedVarint32(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.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedInt64 =
+    jspb.BinaryWriter.prototype.writePackedVarint_;
+
+
+/**
+ * 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.rawWriteVarintFromNum(num);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+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.rawWriteUnsignedVarint32(parseInt(value[i], 10));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedUint64 =
+    jspb.BinaryWriter.prototype.writePackedVarint_;
+
+
+/**
+ * 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.rawWriteVarintFromNum(num);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed signed 32-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSint32 =
+    jspb.BinaryWriter.prototype.writePackedZigzag_;
+
+
+/**
+ * Writes an array numbers to the buffer as a packed signed 64-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSint64 =
+    jspb.BinaryWriter.prototype.writePackedZigzag_;
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed fixed32 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed32 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 4);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteUint32(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed fixed64 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteUint64(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed32 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed32 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 4);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteInt32(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed64 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteInt64(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed float field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFloat =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 4);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteFloat(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed double field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedDouble =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteDouble(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of booleans to the buffer as a packed bool field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<boolean>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedBool =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteBool(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of enums to the buffer as a packed enum field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedEnum =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteEnum(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFixedHash64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteFixedHash64(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedVarintHash64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteVarintHash64(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
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/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..4838911
--- /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..615fc7c
--- /dev/null
+++ b/js/debug_test.js
@@ -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.
+
+goog.setTestOnly();
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.debug');
+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..79095d6
--- /dev/null
+++ b/js/gulpfile.js
@@ -0,0 +1,29 @@
+var gulp = require('gulp');
+var exec = require('child_process').exec;
+
+gulp.task('genproto', function (cb) {
+  exec('../src/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('deps', ['genproto'], 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', ['genproto', '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);
+  });
+});
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..cef9aef
--- /dev/null
+++ b/js/message.js
@@ -0,0 +1,1125 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.json');
+goog.require('goog.object');
+
+// 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;
+};
+
+
+/**
+ * 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.
+
+
+/**
+ * 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_;
+
+
+/**
+ * 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);
+  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(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.ctor) {  // is this a message type?
+        // 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.ctor) {
+    // Message type.
+    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 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.ctor) {
+      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.ctor) {
+      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|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.ctor) {
+      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.ctor) {
+      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 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 (goog.isObject(field1) && goog.isObject(field2)) {
+    var keys = {}, name, extensionObject1, extensionObject2;
+    for (name in field1) {
+      field1.hasOwnProperty(name) && (keys[name] = 0);
+    }
+    for (name in field2) {
+      field2.hasOwnProperty(name) && (keys[name] = 0);
+    }
+    for (name in keys) {
+      var val1 = field1[name], val2 = field2[name];
+      if (goog.isObject(val1) && !goog.isArray(val1)) {
+        if (extensionObject1 !== undefined) {
+          throw new Error('invalid jspb state');
+        }
+        extensionObject1 = goog.object.isEmpty(val1) ? undefined : val1;
+        val1 = undefined;
+      }
+      if (goog.isObject(val2) && !goog.isArray(val2)) {
+        if (extensionObject2 !== undefined) {
+          throw new Error('invalid jspb state');
+        }
+        extensionObject2 = goog.object.isEmpty(val2) ? undefined : val2;
+        val2 = undefined;
+      }
+      if (!jspb.Message.compareFields(val1, val2)) {
+        return false;
+      }
+    }
+    if (extensionObject1 || extensionObject2) {
+      return jspb.Message.compareFields(extensionObject1, extensionObject2);
+    }
+    return true;
+  }
+  // Primitive fields, null and undefined compare as equal.
+  // This also forces booleans and 0/1 to compare as equal to ensure
+  // compatibility with the jspb serializer.
+  return field1 == field2;
+};
+
+
+/**
+ * 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..971ea4f
--- /dev/null
+++ b/js/message_test.js
@@ -0,0 +1,974 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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');
+goog.require('jspb.Message');
+goog.require('proto.jspb.exttest.beta.floatingStrField');
+goog.require('proto.jspb.exttest.floatingMsgField');
+goog.require('proto.jspb.exttest.floatingMsgFieldTwo');
+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.ExtensionMessage');
+goog.require('proto.jspb.test.floatingMsgField');
+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.simple1');
+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.TestExtensionsMessage');
+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');
+
+
+
+
+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('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));
+
+    // These assertions will only work properly in uncompiled mode.
+    // Extension fields defined on proto2 Descriptor messages are filtered out.
+
+    // TODO(haberman): codegen changes to properly ignore descriptor.proto
+    // extensions need to be merged from google3.
+    // assertUndefined(proto.jspb.test.IsExtension['simpleOption']);
+
+    // 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]);
+  });
+
+});
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..be93286
--- /dev/null
+++ b/js/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "google-protobuf",
+  "version": "3.0.0-alpha.5",
+  "description": "Protocol Buffers for JavaScript",
+  "main": "debug.js",
+  "dependencies": {
+    "google-closure-library": "~20160125.0.0",
+    "gulp": "~3.9.0",
+    "jasmine": "~2.4.1"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "./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..8102bab
--- /dev/null
+++ b/js/proto3_test.js
@@ -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.
+
+goog.require('goog.testing.asserts');
+goog.require('proto.jspb.test.ForeignMessage');
+goog.require('proto.jspb.test.Proto3Enum');
+goog.require('proto.jspb.test.TestProto3');
+
+/**
+ * Helper: compare a bytes field to a string with codepoints 0--255.
+ * @param {Uint8Array|string} arr
+ * @param {string} str
+ * @return {boolean}
+ */
+function bytesCompare(arr, str) {
+  if (arr.length != str.length) {
+    return false;
+  }
+  if (typeof arr == 'string') {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr.charCodeAt(i) != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  } else {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr[i] != str.charCodeAt(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(), '');
+
+    // If/when we change bytes fields to return Uint8Array, we'll want to switch
+    // to this assertion instead:
+    //assertEquals(msg.getOptionalBytes() instanceof Uint8Array, true);
+    assertEquals(typeof msg.getOptionalBytes(), 'string');
+
+    assertEquals(msg.getOptionalBytes().length, 0);
+    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('\u00FF\u00FF');
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), '\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('\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);
+  });
+});
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..5f9078e
--- /dev/null
+++ b/js/test.proto
@@ -0,0 +1,212 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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 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/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..e9c5fe6
--- /dev/null
+++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -0,0 +1,117 @@
+#!/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                   \
+)
+
+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..c8681e2
--- /dev/null
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -0,0 +1,283 @@
+#!/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-cpp-descriptors
+         The descriptor.proto is checked in generated, cause it to regenerate.
+   -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_CPP_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-cpp-descriptors )
+      REGEN_CPP_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_CPP_DESCRIPTORS}" == "yes" ]] ; then
+  header "Regenerating the C++ 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
+
+header "Ensuring the ObjC descriptors are current."
+# Find the newest input file (protos, compiler, and the generator script).
+# (these patterns catch some extra stuff, but better to over sample than under)
+readonly NewestInput=$(find \
+   src/google/protobuf/*.proto \
+   src/.libs src/*.la src/protoc \
+   objectivec/generate_descriptors_proto.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 \
+      "${ProtoRootDir}/objectivec/google" \
+      -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
+  echo ">> Newest input is newer than oldest output, regenerating."
+  objectivec/generate_descriptors_proto.sh -j "${NUM_MAKE_JOBS}"
+else
+  echo ">> Newest input is older than oldest output, no need to regenerating."
+fi
+
+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.* )
+      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..8c6396a
--- /dev/null
+++ b/objectivec/GPBArray.h
@@ -0,0 +1,539 @@
+// 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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const int32_t [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const uint32_t [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const int64_t [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const uint64_t [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const float [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const double [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const BOOL [])values
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (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;
+//%
+//%// Initializes the array, copying the values.
+//%- (instancetype)initWithValues:(const TYPE [])values
+//%                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+//%- (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;
+//%
+//%// Initializes the array, copying the values.
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                 rawValues:(const TYPE [])values
+//%                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+//%- (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..60b08ad
--- /dev/null
+++ b/objectivec/GPBArray.m
@@ -0,0 +1,2519 @@
+// 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] initWithValues:NULL count:0] 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 {
+//%  return [self initWithValues:NULL count:0];
+//%}
+//%
+//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array {
+//%  return [self initWithValues:array->_values count:array->_count];
+//%}
+//%
+//%- (instancetype)initWithValues:(const TYPE [])values count:(NSUInteger)count {
+//%  self = [super init];
+//%  if (self) {
+//%    if (count && values) {
+//%      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBInt32Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBUInt32Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBInt64Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBUInt64Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBFloatArray *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const float [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBDoubleArray *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const double [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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] initWithValues:NULL count:0] 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 {
+  return [self initWithValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBBoolArray *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    if (count && values) {
+      _values = malloc(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
+                                         rawValues:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                             count:0] 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 rawValues:NULL count:0];
+}
+
+- (instancetype)initWithValueArray:(GPBEnumArray *)array {
+  return [self initWithValidationFunction:array->_validationFunc
+                                rawValues:array->_values
+                                    count:array->_count];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _validationFunc = (func != NULL ? func : ArrayDefault_IsValidValue);
+    if (count && values) {
+      _values = malloc(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 rawValues:NULL count:0];
+  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..c49c7e2
--- /dev/null
+++ b/objectivec/GPBBootstrap.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.
+
+// 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
+
+// Most uses of protocol buffers don't need field options, by default the
+// static data will be compiled out, define this to 1 to include it. The only
+// time you need this is if you are doing introspection of the protocol buffers.
+#ifndef GPBOBJC_INCLUDE_FIELD_OPTIONS
+#define GPBOBJC_INCLUDE_FIELD_OPTIONS 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 30000
diff --git a/objectivec/GPBCodedInputStream.h b/objectivec/GPBCodedInputStream.h
new file mode 100644
index 0000000..42a0494
--- /dev/null
+++ b/objectivec/GPBCodedInputStream.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.
+
+#import <Foundation/Foundation.h>
+
+@class GPBMessage;
+@class GPBExtensionRegistry;
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Reads and decodes protocol message fields.
+// Subclassing of GPBCodedInputStream is NOT supported.
+@interface GPBCodedInputStream : NSObject
+
++ (instancetype)streamWithData:(NSData *)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;
+
+- (double)readDouble;
+- (float)readFloat;
+- (uint64_t)readUInt64;
+- (uint32_t)readUInt32;
+- (int64_t)readInt64;
+- (int32_t)readInt32;
+- (uint64_t)readFixed64;
+- (uint32_t)readFixed32;
+- (int32_t)readEnum;
+- (int32_t)readSFixed32;
+- (int64_t)readSFixed64;
+- (int32_t)readSInt32;
+- (int64_t)readSInt64;
+- (BOOL)readBool;
+- (NSString *)readString;
+- (NSData *)readBytes;
+
+// Read an embedded message field value from the stream.
+- (void)readMessage:(GPBMessage *)message
+    extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry;
+
+// Reads and discards a single field, given its tag value. Returns NO if the
+// tag is an endgroup tag, in which case nothing is skipped.  Otherwise,
+// returns YES.
+- (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;
+
+// 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 NSParseErrorException if value does not match the last tag.
+- (void)checkLastTagWas:(int32_t)value;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
new file mode 100644
index 0000000..fd87783
--- /dev/null
+++ b/objectivec/GPBCodedInputStream.m
@@ -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.
+
+#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];
+    if (!result) {
+      result = @"";
+#ifdef DEBUG
+      // https://developers.google.com/protocol-buffers/docs/proto#scalar
+      NSLog(@"UTF8 failure, is some field type 'string' when it should be "
+            @"'bytes'?");
+#endif
+    }
+    state->bufferPos += size;
+  }
+  return result;
+}
+
+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;
+    }
+  }
+}
+
+- (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..a5aef17
--- /dev/null
+++ b/objectivec/GPBCodedOutputStream.h
@@ -0,0 +1,342 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+
+@interface GPBCodedOutputStream : NSObject
+
+// Creates a new stream to write into data.  Data must be sized to fit or it
+// will error when it runs out of space.
++ (instancetype)streamWithData:(NSMutableData *)data;
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output;
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output
+                            bufferSize:(size_t)bufferSize;
+
+- (instancetype)initWithData:(NSMutableData *)data;
+- (instancetype)initWithOutputStream:(NSOutputStream *)output;
+- (instancetype)initWithOutputStream:(NSOutputStream *)output
+                          bufferSize:(size_t)bufferSize;
+
+- (void)flush;
+
+- (void)writeRawByte:(uint8_t)value;
+
+- (void)writeTag:(uint32_t)fieldNumber format:(GPBWireFormat)format;
+
+- (void)writeRawLittleEndian32:(int32_t)value;
+- (void)writeRawLittleEndian64:(int64_t)value;
+
+- (void)writeRawVarint32:(int32_t)value;
+- (void)writeRawVarint64:(int64_t)value;
+
+// Note that this will truncate 64 bit values to 32.
+- (void)writeRawVarintSizeTAs32:(size_t)value;
+
+- (void)writeRawData:(NSData *)data;
+- (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.
+
+- (void)writeDouble:(int32_t)fieldNumber value:(double)value;
+- (void)writeDoubleArray:(int32_t)fieldNumber
+                  values:(GPBDoubleArray *)values
+                     tag:(uint32_t)tag;
+- (void)writeDoubleNoTag:(double)value;
+
+- (void)writeFloat:(int32_t)fieldNumber value:(float)value;
+- (void)writeFloatArray:(int32_t)fieldNumber
+                 values:(GPBFloatArray *)values
+                    tag:(uint32_t)tag;
+- (void)writeFloatNoTag:(float)value;
+
+- (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value;
+- (void)writeUInt64Array:(int32_t)fieldNumber
+                  values:(GPBUInt64Array *)values
+                     tag:(uint32_t)tag;
+- (void)writeUInt64NoTag:(uint64_t)value;
+
+- (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value;
+- (void)writeInt64Array:(int32_t)fieldNumber
+                 values:(GPBInt64Array *)values
+                    tag:(uint32_t)tag;
+- (void)writeInt64NoTag:(int64_t)value;
+
+- (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value;
+- (void)writeInt32Array:(int32_t)fieldNumber
+                 values:(GPBInt32Array *)values
+                    tag:(uint32_t)tag;
+- (void)writeInt32NoTag:(int32_t)value;
+
+- (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value;
+- (void)writeUInt32Array:(int32_t)fieldNumber
+                  values:(GPBUInt32Array *)values
+                     tag:(uint32_t)tag;
+- (void)writeUInt32NoTag:(uint32_t)value;
+
+- (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value;
+- (void)writeFixed64Array:(int32_t)fieldNumber
+                   values:(GPBUInt64Array *)values
+                      tag:(uint32_t)tag;
+- (void)writeFixed64NoTag:(uint64_t)value;
+
+- (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value;
+- (void)writeFixed32Array:(int32_t)fieldNumber
+                   values:(GPBUInt32Array *)values
+                      tag:(uint32_t)tag;
+- (void)writeFixed32NoTag:(uint32_t)value;
+
+- (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value;
+- (void)writeSInt32Array:(int32_t)fieldNumber
+                  values:(GPBInt32Array *)values
+                     tag:(uint32_t)tag;
+- (void)writeSInt32NoTag:(int32_t)value;
+
+- (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value;
+- (void)writeSInt64Array:(int32_t)fieldNumber
+                  values:(GPBInt64Array *)values
+                     tag:(uint32_t)tag;
+- (void)writeSInt64NoTag:(int64_t)value;
+
+- (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value;
+- (void)writeSFixed64Array:(int32_t)fieldNumber
+                    values:(GPBInt64Array *)values
+                       tag:(uint32_t)tag;
+- (void)writeSFixed64NoTag:(int64_t)value;
+
+- (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value;
+- (void)writeSFixed32Array:(int32_t)fieldNumber
+                    values:(GPBInt32Array *)values
+                       tag:(uint32_t)tag;
+- (void)writeSFixed32NoTag:(int32_t)value;
+
+- (void)writeBool:(int32_t)fieldNumber value:(BOOL)value;
+- (void)writeBoolArray:(int32_t)fieldNumber
+                values:(GPBBoolArray *)values
+                   tag:(uint32_t)tag;
+- (void)writeBoolNoTag:(BOOL)value;
+
+- (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value;
+- (void)writeEnumArray:(int32_t)fieldNumber
+                values:(GPBEnumArray *)values
+                   tag:(uint32_t)tag;
+- (void)writeEnumNoTag:(int32_t)value;
+
+- (void)writeString:(int32_t)fieldNumber value:(NSString *)value;
+- (void)writeStringArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeStringNoTag:(NSString *)value;
+
+- (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value;
+- (void)writeMessageArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeMessageNoTag:(GPBMessage *)value;
+
+- (void)writeBytes:(int32_t)fieldNumber value:(NSData *)value;
+- (void)writeBytesArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeBytesNoTag:(NSData *)value;
+
+- (void)writeGroup:(int32_t)fieldNumber
+             value:(GPBMessage *)value;
+- (void)writeGroupArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeGroupNoTag:(int32_t)fieldNumber
+                  value:(GPBMessage *)value;
+
+- (void)writeUnknownGroup:(int32_t)fieldNumber
+                    value:(GPBUnknownFieldSet *)value;
+- (void)writeUnknownGroupArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (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
+
+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
+
+// Write methods for types that can be in packed arrays.
+//%PDDM-DEFINE _WRITE_PACKABLE_DECLS(NAME, ARRAY_TYPE, TYPE)
+//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value;
+//%- (void)write##NAME##Array:(int32_t)fieldNumber
+//%       NAME$S     values:(GPB##ARRAY_TYPE##Array *)values
+//%       NAME$S        tag:(uint32_t)tag;
+//%- (void)write##NAME##NoTag:(TYPE)value;
+//%
+// Write methods for types that aren't in packed arrays.
+//%PDDM-DEFINE _WRITE_UNPACKABLE_DECLS(NAME, TYPE)
+//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value;
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray *)values;
+//%- (void)write##NAME##NoTag:(TYPE)value;
+//%
+// Special write methods for Groups.
+//%PDDM-DEFINE _WRITE_GROUP_DECLS(NAME, TYPE)
+//%- (void)write##NAME:(int32_t)fieldNumber
+//%       NAME$S value:(TYPE)value;
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray *)values;
+//%- (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..70142e6
--- /dev/null
+++ b/objectivec/GPBCodedOutputStream.m
@@ -0,0 +1,1232 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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"
+
+#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];
+}
+
+- (instancetype)initWithOutputStream:(NSOutputStream *)output
+                          bufferSize:(size_t)bufferSize {
+  NSMutableData *data = [NSMutableData dataWithLength:bufferSize];
+  return [self initWithOutputStream:output 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
+                            bufferSize:(size_t)bufferSize {
+  return [[[self alloc] initWithOutputStream:output
+                                  bufferSize:bufferSize] autorelease];
+}
+
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output {
+  return [[[self alloc] initWithOutputStream:output
+                                  bufferSize:PAGE_SIZE] 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/GPBDescriptor.h b/objectivec/GPBDescriptor.h
new file mode 100644
index 0000000..360afe9
--- /dev/null
+++ b/objectivec/GPBDescriptor.h
@@ -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.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBRuntimeTypes.h"
+
+@class GPBEnumDescriptor;
+@class GPBFieldDescriptor;
+@class GPBFieldOptions;
+@class GPBFileDescriptor;
+@class GPBOneofDescriptor;
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSInteger, GPBFileSyntax) {
+  GPBFileSyntaxUnknown = 0,
+  GPBFileSyntaxProto2 = 2,
+  GPBFileSyntaxProto3 = 3,
+};
+
+typedef NS_ENUM(NSInteger, 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 *fields;
+@property(nonatomic, readonly, strong, nullable) NSArray *oneofs;
+@property(nonatomic, readonly, strong, nullable) NSArray *enums;
+@property(nonatomic, readonly, nullable) const GPBExtensionRange *extensionRanges;
+@property(nonatomic, readonly) NSUInteger 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;
+- (nullable GPBEnumDescriptor *)enumWithName:(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 *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;
+
+@property(nonatomic, readonly, nullable) GPBFieldOptions *fieldOptions;
+
+// 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..bae9187
--- /dev/null
+++ b/objectivec/GPBDescriptor.m
@@ -0,0 +1,997 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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"
+#import "google/protobuf/Descriptor.pbobjc.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_;
+  NSArray *enums_;
+  GPBFileDescriptor *file_;
+  BOOL wireFormat_;
+}
+
+@synthesize messageClass = messageClass_;
+@synthesize fields = fields_;
+@synthesize oneofs = oneofs_;
+@synthesize enums = enums_;
+@synthesize extensionRanges = extensionRanges_;
+@synthesize extensionRangesCount = extensionRangesCount_;
+@synthesize file = file_;
+@synthesize wireFormat = wireFormat_;
+
++ (instancetype)
+    allocDescriptorForClass:(Class)messageClass
+                  rootClass:(Class)rootClass
+                       file:(GPBFileDescriptor *)file
+                     fields:(GPBMessageFieldDescription *)fieldDescriptions
+                 fieldCount:(NSUInteger)fieldCount
+                     oneofs:(GPBMessageOneofDescription *)oneofDescriptions
+                 oneofCount:(NSUInteger)oneofCount
+                      enums:(GPBMessageEnumDescription *)enumDescriptions
+                  enumCount:(NSUInteger)enumCount
+                     ranges:(const GPBExtensionRange *)ranges
+                 rangeCount:(NSUInteger)rangeCount
+                storageSize:(size_t)storageSize
+                 wireFormat:(BOOL)wireFormat {
+  NSMutableArray *fields = nil;
+  NSMutableArray *oneofs = nil;
+  NSMutableArray *enums = nil;
+  NSMutableArray *extensionRanges = nil;
+  GPBFileSyntax syntax = file.syntax;
+  for (NSUInteger i = 0; i < fieldCount; ++i) {
+    if (fields == nil) {
+      fields = [[NSMutableArray alloc] initWithCapacity:fieldCount];
+    }
+    GPBFieldDescriptor *fieldDescriptor = [[GPBFieldDescriptor alloc]
+        initWithFieldDescription:&fieldDescriptions[i]
+                       rootClass:rootClass
+                          syntax:syntax];
+    [fields addObject:fieldDescriptor];
+    [fieldDescriptor release];
+  }
+  for (NSUInteger i = 0; i < oneofCount; ++i) {
+    if (oneofs == nil) {
+      oneofs = [[NSMutableArray alloc] initWithCapacity:oneofCount];
+    }
+    GPBMessageOneofDescription *oneofDescription = &oneofDescriptions[i];
+    NSArray *fieldsForOneof =
+        NewFieldsArrayForHasIndex(oneofDescription->index, fields);
+    GPBOneofDescriptor *oneofDescriptor =
+        [[GPBOneofDescriptor alloc] initWithOneofDescription:oneofDescription
+                                                      fields:fieldsForOneof];
+    [oneofs addObject:oneofDescriptor];
+    [oneofDescriptor release];
+    [fieldsForOneof release];
+  }
+  for (NSUInteger i = 0; i < enumCount; ++i) {
+    if (enums == nil) {
+      enums = [[NSMutableArray alloc] initWithCapacity:enumCount];
+    }
+    GPBEnumDescriptor *enumDescriptor =
+        enumDescriptions[i].enumDescriptorFunc();
+    [enums addObject:enumDescriptor];
+  }
+
+  GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
+                                                     file:file
+                                                   fields:fields
+                                                   oneofs:oneofs
+                                                    enums:enums
+                                          extensionRanges:ranges
+                                     extensionRangesCount:rangeCount
+                                              storageSize:storageSize
+                                               wireFormat:wireFormat];
+  [fields release];
+  [oneofs release];
+  [enums release];
+  [extensionRanges release];
+  return descriptor;
+}
+
++ (instancetype)
+    allocDescriptorForClass:(Class)messageClass
+                  rootClass:(Class)rootClass
+                       file:(GPBFileDescriptor *)file
+                     fields:(GPBMessageFieldDescription *)fieldDescriptions
+                 fieldCount:(NSUInteger)fieldCount
+                     oneofs:(GPBMessageOneofDescription *)oneofDescriptions
+                 oneofCount:(NSUInteger)oneofCount
+                      enums:(GPBMessageEnumDescription *)enumDescriptions
+                  enumCount:(NSUInteger)enumCount
+                     ranges:(const GPBExtensionRange *)ranges
+                 rangeCount:(NSUInteger)rangeCount
+                storageSize:(size_t)storageSize
+                 wireFormat:(BOOL)wireFormat
+        extraTextFormatInfo:(const char *)extraTextFormatInfo {
+  GPBDescriptor *descriptor = [self allocDescriptorForClass:messageClass
+                                                  rootClass:rootClass
+                                                       file:file
+                                                     fields:fieldDescriptions
+                                                 fieldCount:fieldCount
+                                                     oneofs:oneofDescriptions
+                                                 oneofCount:oneofCount
+                                                      enums:enumDescriptions
+                                                  enumCount:enumCount
+                                                     ranges:ranges
+                                                 rangeCount:rangeCount
+                                                storageSize:storageSize
+                                                 wireFormat:wireFormat];
+  // 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 descriptor->fields_) {
+      if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
+        objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey,
+                                 extraInfoValue,
+                                 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+      }
+    }
+  }
+  return descriptor;
+}
+
+- (instancetype)initWithClass:(Class)messageClass
+                         file:(GPBFileDescriptor *)file
+                       fields:(NSArray *)fields
+                       oneofs:(NSArray *)oneofs
+                        enums:(NSArray *)enums
+              extensionRanges:(const GPBExtensionRange *)extensionRanges
+         extensionRangesCount:(NSUInteger)extensionRangesCount
+                  storageSize:(size_t)storageSize
+                   wireFormat:(BOOL)wireFormat {
+  if ((self = [super init])) {
+    messageClass_ = messageClass;
+    file_ = file;
+    fields_ = [fields retain];
+    oneofs_ = [oneofs retain];
+    enums_ = [enums retain];
+    extensionRanges_ = extensionRanges;
+    extensionRangesCount_ = extensionRangesCount;
+    storageSize_ = storageSize;
+    wireFormat_ = wireFormat;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [fields_ release];
+  [oneofs_ release];
+  [enums_ release];
+  [super dealloc];
+}
+
+- (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;
+}
+
+- (GPBEnumDescriptor *)enumWithName:(NSString *)name {
+  for (GPBEnumDescriptor *descriptor in enums_) {
+    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)initWithOneofDescription:
+                    (GPBMessageOneofDescription *)oneofDescription
+                                  fields:(NSArray *)fields {
+  self = [super init];
+  if (self) {
+    NSAssert(oneofDescription->index < 0, @"Should always be <0");
+    oneofDescription_ = oneofDescription;
+    fields_ = [fields retain];
+    for (GPBFieldDescriptor *fieldDesc in fields) {
+      fieldDesc->containingOneof_ = self;
+    }
+
+    caseSel_ = SelFromStrings(NULL, oneofDescription->name, "OneOfCase", NO);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [fields_ release];
+  [super dealloc];
+}
+
+- (NSString *)name {
+  return @(oneofDescription_->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_;
+  GPBFieldOptions *fieldOptions_;
+
+  // 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 fieldOptions = fieldOptions_;
+@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:
+                    (GPBMessageFieldDescription *)description
+                               rootClass:(Class)rootClass
+                                  syntax:(GPBFileSyntax)syntax {
+  if ((self = [super init])) {
+    description_ = description;
+    getSel_ = sel_getUid(description->name);
+    setSel_ = SelFromStrings("set", description->name, NULL, YES);
+
+    GPBDataType dataType = description->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, description->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 ((description->hasIndex >= 0) &&
+          (description->hasIndex != GPBNoHasBit) &&
+          ((syntax != GPBFileSyntaxProto3) || isMessage)) {
+        hasOrCountSel_ = SelFromStrings("has", description->name, NULL, NO);
+        setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES);
+      }
+    }
+
+    // Extra type specific data.
+    if (isMessage) {
+      const char *className = description->dataTypeSpecific.className;
+      msgClass_ = objc_getClass(className);
+      NSAssert(msgClass_, @"Class %s not defined", className);
+    } else if (dataType == GPBDataTypeEnum) {
+      if ((description_->flags & GPBFieldHasEnumDescriptor) != 0) {
+        enumHandling_.enumDescriptor_ =
+            description->dataTypeSpecific.enumDescFunc();
+      } else {
+        enumHandling_.enumVerifier_ =
+            description->dataTypeSpecific.enumVerifier;
+      }
+    }
+
+    // Non map<>/repeated fields can have defaults.
+    if (!isMapOrArray) {
+      defaultValue_ = 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];
+        }
+      }
+    }
+
+    // FieldOptions stored as a length prefixed (network byte order) c-escaped
+    // string in descriptor records.
+    if (description->fieldOptions) {
+      uint8_t *optionsBytes = (uint8_t *)description->fieldOptions;
+      uint32_t optionsLength = *((uint32_t *)optionsBytes);
+      optionsLength = ntohl(optionsLength);
+      if (optionsLength > 0) {
+        optionsBytes += sizeof(optionsLength);
+        NSData *optionsData = [NSData dataWithBytesNoCopy:optionsBytes
+                                                   length:optionsLength
+                                             freeWhenDone:NO];
+        GPBExtensionRegistry *registry = [rootClass extensionRegistry];
+        fieldOptions_ = [[GPBFieldOptions parseFromData:optionsData
+                                      extensionRegistry:registry
+                                                  error:NULL] retain];
+      }
+    }
+  }
+  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 (NSUInteger 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_;
+  GPBMessageEnumValueDescription *valueDescriptions_;
+  NSUInteger valueDescriptionsCount_;
+  GPBEnumValidationFunc enumVerifier_;
+  const uint8_t *extraTextFormatInfo_;
+}
+
+@synthesize name = name_;
+@synthesize enumVerifier = enumVerifier_;
+
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                    values:(GPBMessageEnumValueDescription *)valueDescriptions
+                valueCount:(NSUInteger)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier {
+  GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
+                                                      values:valueDescriptions
+                                                  valueCount:valueCount
+                                                enumVerifier:enumVerifier];
+  return descriptor;
+}
+
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                    values:(GPBMessageEnumValueDescription *)valueDescriptions
+                valueCount:(NSUInteger)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier
+       extraTextFormatInfo:(const char *)extraTextFormatInfo {
+  // Call the common case.
+  GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
+                                                        values:valueDescriptions
+                                                    valueCount:valueCount
+                                                  enumVerifier:enumVerifier];
+  // Set the extra info.
+  descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
+  return descriptor;
+}
+
+- (instancetype)initWithName:(NSString *)name
+                      values:(GPBMessageEnumValueDescription *)valueDescriptions
+                  valueCount:(NSUInteger)valueCount
+                enumVerifier:(GPBEnumValidationFunc)enumVerifier {
+  if ((self = [super init])) {
+    name_ = [name copy];
+    valueDescriptions_ = valueDescriptions;
+    valueDescriptionsCount_ = valueCount;
+    enumVerifier_ = enumVerifier;
+  }
+  return self;
+}
+
+- (NSString *)enumNameForValue:(int32_t)number {
+  for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) {
+    GPBMessageEnumValueDescription *scan = &valueDescriptions_[i];
+    if ((scan->number == number) && (scan->name != NULL)) {
+      NSString *fullName =
+          [NSString stringWithFormat:@"%@_%s", name_, scan->name];
+      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;
+
+  // Find it.
+  for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) {
+    GPBMessageEnumValueDescription *scan = &valueDescriptions_[i];
+    if ((scan->name != NULL) && (strcmp(nameAsCStr, scan->name) == 0)) {
+      if (outValue) {
+        *outValue = scan->number;
+      }
+      return YES;
+    }
+  }
+  return NO;
+}
+
+- (void)dealloc {
+  [name_ release];
+  [super dealloc];
+}
+
+- (NSString *)textFormatNameForValue:(int32_t)number {
+  // Find the EnumValue descriptor and its index.
+  GPBMessageEnumValueDescription *valueDescriptor = NULL;
+  NSUInteger valueDescriptorIndex;
+  for (valueDescriptorIndex = 0; valueDescriptorIndex < valueDescriptionsCount_;
+       ++valueDescriptorIndex) {
+    GPBMessageEnumValueDescription *scan =
+        &valueDescriptions_[valueDescriptorIndex];
+    if (scan->number == number) {
+      valueDescriptor = scan;
+      break;
+    }
+  }
+
+  // If we didn't find it, or names were disable at proto compile time, nothing
+  // we can do.
+  if (!valueDescriptor || !valueDescriptor->name) {
+    return nil;
+  }
+
+  NSString *result = nil;
+  // Naming adds an underscore between enum name and value name, skip that also.
+  NSString *shortName = @(valueDescriptor->name);
+
+  // 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..7987d92
--- /dev/null
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -0,0 +1,318 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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(uint32_t, GPBFieldFlags) {
+  // These map to standard protobuf concepts.
+  GPBFieldRequired        = 1 << 0,
+  GPBFieldRepeated        = 1 << 1,
+  GPBFieldPacked          = 1 << 2,
+  GPBFieldOptional        = 1 << 3,
+  GPBFieldHasDefaultValue = 1 << 4,
+
+  // 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,
+
+  // Indicates the field needs custom handling for the TextFormat name, if not
+  // set, the name can be derived from the ObjC name.
+  GPBFieldTextFormatNameCustom = 1 << 16,
+  // Indicates the field has an enum descriptor.
+  GPBFieldHasEnumDescriptor = 1 << 17,
+};
+
+// Describes a single field in a protobuf as it is represented as an ivar.
+typedef struct GPBMessageFieldDescription {
+  // Name of ivar.
+  const char *name;
+  // 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.
+  //   = 0: no storage used.
+  //   < 0: in a oneOf, use a full int32 to record the field active.
+  int32_t hasIndex;
+  // Field flags. Use accessor functions below.
+  GPBFieldFlags flags;
+  // Data type of the ivar.
+  GPBDataType dataType;
+  // Offset of the variable into it's structure struct.
+  size_t offset;
+  // FieldOptions protobuf, serialized as string.
+  const char *fieldOptions;
+
+  GPBGenericValue defaultValue;  // Default value for the ivar.
+  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;
+} GPBMessageFieldDescription;
+
+// Describes a oneof.
+typedef struct GPBMessageOneofDescription {
+  // Name of this enum oneof.
+  const char *name;
+  // The index of this oneof in the has_storage.
+  int32_t index;
+} GPBMessageOneofDescription;
+
+// Describes an enum type defined in a .proto file.
+typedef struct GPBMessageEnumDescription {
+  GPBEnumDescriptorFunc enumDescriptorFunc;
+} GPBMessageEnumDescription;
+
+// Describes an individual enum constant of a particular type.
+typedef struct GPBMessageEnumValueDescription {
+  // Name of this enum constant.
+  const char *name;
+  // Numeric value of this enum constant.
+  int32_t number;
+} GPBMessageEnumValueDescription;
+
+// Describes attributes of the extension.
+typedef NS_OPTIONS(uint32_t, GPBExtensionOptions) {
+  // These map to standard protobuf concepts.
+  GPBExtensionRepeated      = 1 << 0,
+  GPBExtensionPacked        = 1 << 1,
+  GPBExtensionSetWireFormat = 1 << 2,
+};
+
+// An extension
+typedef struct GPBExtensionDescription {
+  const char *singletonName;
+  GPBDataType dataType;
+  const char *extendedClass;
+  int32_t fieldNumber;
+  GPBGenericValue defaultValue;
+  const char *messageOrGroupClassName;
+  GPBExtensionOptions options;
+  GPBEnumDescriptorFunc enumDescriptorFunc;
+} GPBExtensionDescription;
+
+@interface GPBDescriptor () {
+ @package
+  NSArray *fields_;
+  NSArray *oneofs_;
+  size_t storageSize_;
+}
+
+// fieldDescriptions, enumDescriptions, rangeDescriptions, and
+// extraTextFormatInfo have to be long lived, they are held as raw pointers.
++ (instancetype)
+    allocDescriptorForClass:(Class)messageClass
+                  rootClass:(Class)rootClass
+                       file:(GPBFileDescriptor *)file
+                     fields:(GPBMessageFieldDescription *)fieldDescriptions
+                 fieldCount:(NSUInteger)fieldCount
+                     oneofs:(GPBMessageOneofDescription *)oneofDescriptions
+                 oneofCount:(NSUInteger)oneofCount
+                      enums:(GPBMessageEnumDescription *)enumDescriptions
+                  enumCount:(NSUInteger)enumCount
+                     ranges:(const GPBExtensionRange *)ranges
+                 rangeCount:(NSUInteger)rangeCount
+                storageSize:(size_t)storageSize
+                 wireFormat:(BOOL)wireFormat;
++ (instancetype)
+    allocDescriptorForClass:(Class)messageClass
+                  rootClass:(Class)rootClass
+                       file:(GPBFileDescriptor *)file
+                     fields:(GPBMessageFieldDescription *)fieldDescriptions
+                 fieldCount:(NSUInteger)fieldCount
+                     oneofs:(GPBMessageOneofDescription *)oneofDescriptions
+                 oneofCount:(NSUInteger)oneofCount
+                      enums:(GPBMessageEnumDescription *)enumDescriptions
+                  enumCount:(NSUInteger)enumCount
+                     ranges:(const GPBExtensionRange *)ranges
+                 rangeCount:(NSUInteger)rangeCount
+                storageSize:(size_t)storageSize
+                 wireFormat:(BOOL)wireFormat
+        extraTextFormatInfo:(const char *)extraTextFormatInfo;
+
+- (instancetype)initWithClass:(Class)messageClass
+                         file:(GPBFileDescriptor *)file
+                       fields:(NSArray *)fields
+                       oneofs:(NSArray *)oneofs
+                        enums:(NSArray *)enums
+              extensionRanges:(const GPBExtensionRange *)ranges
+         extensionRangesCount:(NSUInteger)rangeCount
+                  storageSize:(size_t)storage
+                   wireFormat:(BOOL)wireFormat;
+
+@end
+
+@interface GPBFileDescriptor ()
+- (instancetype)initWithPackage:(NSString *)package
+                         syntax:(GPBFileSyntax)syntax;
+@end
+
+@interface GPBOneofDescriptor () {
+ @package
+  GPBMessageOneofDescription *oneofDescription_;
+  NSArray *fields_;
+
+  SEL caseSel_;
+}
+- (instancetype)initWithOneofDescription:
+                    (GPBMessageOneofDescription *)oneofDescription
+                                  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:
+                    (GPBMessageFieldDescription *)description
+                               rootClass:(Class)rootClass
+                                  syntax:(GPBFileSyntax)syntax;
+@end
+
+@interface GPBEnumDescriptor ()
+// valueDescriptions and extraTextFormatInfo have to be long lived, they are
+// held as raw pointers.
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                    values:(GPBMessageEnumValueDescription *)valueDescriptions
+                valueCount:(NSUInteger)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier;
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                    values:(GPBMessageEnumValueDescription *)valueDescriptions
+                valueCount:(NSUInteger)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier
+       extraTextFormatInfo:(const char *)extraTextFormatInfo;
+
+- (instancetype)initWithName:(NSString *)name
+                      values:(GPBMessageEnumValueDescription *)valueDescriptions
+                  valueCount:(NSUInteger)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;
+}
+
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBDictionary.h b/objectivec/GPBDictionary.h
new file mode 100644
index 0000000..6961cfc
--- /dev/null
+++ b/objectivec/GPBDictionary.h
@@ -0,0 +1,2237 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(uint32_t)key;
++ (instancetype)dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const uint32_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const uint32_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (id)objectForKey:(uint32_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint32_t key, id object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(id)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 : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(int32_t)key;
++ (instancetype)dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const int32_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const int32_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (id)objectForKey:(int32_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int32_t key, id object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(id)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 : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(uint64_t)key;
++ (instancetype)dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const uint64_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const uint64_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (id)objectForKey:(uint64_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint64_t key, id object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(id)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 : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(int64_t)key;
++ (instancetype)dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const int64_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const int64_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (id)objectForKey:(int64_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int64_t key, id object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(id)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 : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(BOOL)key;
++ (instancetype)dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const BOOL [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const BOOL [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (id)objectForKey:(BOOL)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(BOOL key, id object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary;
+
+- (void)setObject:(id)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, id)
+//%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_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary : 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..6baa2a1
--- /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.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..634c336
--- /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.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..0363c70
--- /dev/null
+++ b/objectivec/GPBExtensionRegistry.h
@@ -0,0 +1,67 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 an
+// ExtensionRegistry 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 *Root classes provide +extensionRegistry for the extensions defined in a
+// given file *and* all files it imports.  You can also create a
+// GPBExtensionRegistry, and merge those registries to handle parsing extensions
+// defined from non overlapping files.
+//
+//    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];
+//
+@interface GPBExtensionRegistry : NSObject<NSCopying>
+
+- (void)addExtension:(GPBExtensionDescriptor *)extension;
+- (void)addExtensions:(GPBExtensionRegistry *)registry;
+
+- (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..332393e
--- /dev/null
+++ b/objectivec/GPBMessage.h
@@ -0,0 +1,177 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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;
+
+typedef NS_ENUM(NSInteger, GPBMessageErrorCode) {
+  GPBMessageErrorCodeMalformedData = -100,
+  GPBMessageErrorCodeMissingRequiredField = -101,
+};
+
+// 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 |userInfo| dictionary.
+#ifdef DEBUG
+extern NSString *const GPBExceptionMessageKey;
+#endif  // DEBUG
+
+CF_EXTERN_C_END
+
+@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.
+
+@property(nonatomic, copy, nullable) GPBUnknownFieldSet *unknownFields;
+
+// Are all required fields in the message and all embedded messages set.
+@property(nonatomic, readonly, getter=isInitialized) BOOL initialized;
+
+// Returns an autoreleased instance.
++ (instancetype)message;
+
+// Create a message based on a variety of inputs.  If there is a data parse
+// error, nil is returned and if not NULL, errorPtr is filled in.
+// NOTE: In DEBUG ONLY, the message is also checked for all required field,
+// if one is missing, the parse will fail (returning nil, filling in errorPtr).
++ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr;
++ (instancetype)parseFromData:(NSData *)data
+            extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry
+                        error:(NSError **)errorPtr;
++ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
+                        extensionRegistry:
+                            (nullable GPBExtensionRegistry *)extensionRegistry
+                                    error:(NSError **)errorPtr;
+
+// Create a message based on delimited input.  If there is a data parse
+// error, nil is returned and if not NULL, errorPtr is filled in.
++ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
+                                 extensionRegistry:
+                                     (nullable GPBExtensionRegistry *)extensionRegistry
+                                             error:(NSError **)errorPtr;
+
+// If there is a data parse error, nil is returned and if not NULL, errorPtr is
+// filled in.
+// NOTE: In DEBUG ONLY, the message is also checked for all required field,
+// if one is missing, the parse will fail (returning nil, filling in errorPtr).
+- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr;
+- (instancetype)initWithData:(NSData *)data
+           extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry
+                       error:(NSError **)errorPtr;
+- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
+                       extensionRegistry:
+                           (nullable GPBExtensionRegistry *)extensionRegistry
+                                   error:(NSError **)errorPtr;
+
+// Serializes the message and writes it to output.
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
+- (void)writeToOutputStream:(NSOutputStream *)output;
+
+// Serializes the message and writes it to output, but writes the size of the
+// message as a variant before writing the message.
+- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
+- (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
+
+// Serializes the message to an NSData. Note that this value is not cached, so
+// if you are using it repeatedly, cache it yourself. If there is an error
+// while generating the data, nil is returned.
+// NOTE: In DEBUG ONLY, the message is also checked for all required field,
+// if one is missing, nil will be returned.
+- (nullable NSData *)data;
+
+// Same as -[data], except a delimiter is added to the start of the data
+// indicating the size of the message data that follows.
+- (NSData *)delimitedData;
+
+// Returns the size of the object if it were serialized.
+// This is not a cached value. If you are following a pattern like this:
+//   size_t size = [aMsg serializedSize];
+//   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
+//   [foo writeSize:size];
+//   [foo appendData:[aMsg data]];
+// you would be better doing:
+//   NSData *data = [aMsg data];
+//   NSUInteger size = [aMsg length];
+//   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
+//   [foo writeSize:size];
+//   [foo appendData:data];
+- (size_t)serializedSize;
+
+// Return the descriptor for the message
++ (GPBDescriptor *)descriptor;
+- (GPBDescriptor *)descriptor;
+
+// Extensions use boxed values (NSNumbers) for PODs, NSMutableArrays for
+// repeated. If the extension is a Message one will be auto created for you
+// and returned similar to fields.
+- (BOOL)hasExtension:(GPBExtensionDescriptor *)extension;
+- (nullable id)getExtension:(GPBExtensionDescriptor *)extension;
+- (void)setExtension:(GPBExtensionDescriptor *)extension value:(nullable id)value;
+- (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value;
+- (void)setExtension:(GPBExtensionDescriptor *)extension
+               index:(NSUInteger)index
+               value:(id)value;
+- (void)clearExtension:(GPBExtensionDescriptor *)extension;
+
+// Resets all fields 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..fdb695e
--- /dev/null
+++ b/objectivec/GPBMessage.m
@@ -0,0 +1,3193 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.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";
+
+#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
+
+//
+// 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.
+    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.
+    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
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:0
+                                             wireFormat:NO];
+  }
+  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]));
+
+    readOnlySemaphore_ = dispatch_semaphore_create(1);
+  }
+
+  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.");
+  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.
+  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 release];
+    message = nil;
+    if (errorPtr) {
+      *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                         exception.reason);
+    }
+  }
+#ifdef DEBUG
+  if (message && !message.initialized) {
+    [message release];
+    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: {
+          BOOL *selfValPtr = (BOOL *)&selfStorage[fieldOffset];
+          BOOL *otherValPtr = (BOOL *)&otherStorage[fieldOffset];
+          if (*selfValPtr != *otherValPtr) {
+            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: {
+          BOOL *valPtr = (BOOL *)&storage[fieldOffset];
+          result = prime * result + *valPtr;
+          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 = oneof->oneofDescription_->index;
+          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..b7e24fc
--- /dev/null
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -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.
+
+// 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
+  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
+
+// 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..e9cbfb4
--- /dev/null
+++ b/objectivec/GPBProtocolBuffers.m
@@ -0,0 +1,62 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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"
+
+#import "google/protobuf/Descriptor.pbobjc.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..e2af5d9
--- /dev/null
+++ b/objectivec/GPBRootObject.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>
+
+@class GPBExtensionRegistry;
+
+NS_ASSUME_NONNULL_BEGIN
+
+// All Root Objects derive from GPBRootObject. It supplies a registry
+// for derived classes to register their extensions to.
+@interface GPBRootObject : NSObject
+
+// Per class registry.
++ (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..e91d86a
--- /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 enum {
+  GPBDataTypeBool = 0,
+  GPBDataTypeFixed32,
+  GPBDataTypeSFixed32,
+  GPBDataTypeFloat,
+  GPBDataTypeFixed64,
+  GPBDataTypeSFixed64,
+  GPBDataTypeDouble,
+  GPBDataTypeInt32,
+  GPBDataTypeInt64,
+  GPBDataTypeSInt32,
+  GPBDataTypeSInt64,
+  GPBDataTypeUInt32,
+  GPBDataTypeUInt64,
+  GPBDataTypeBytes,
+  GPBDataTypeString,
+  GPBDataTypeMessage,
+  GPBDataTypeGroup,
+  GPBDataTypeEnum,
+} GPBDataType;
+
+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..12d72a9
--- /dev/null
+++ b/objectivec/GPBUnknownField.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.
+
+#import <Foundation/Foundation.h>
+
+@class GPBCodedOutputStream;
+@class GPBUInt32Array;
+@class GPBUInt64Array;
+@class GPBUnknownFieldSet;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GPBUnknownField : NSObject<NSCopying>
+
+@property(nonatomic, readonly, assign) int32_t number;
+
+// Only one of these will be set.
+@property(nonatomic, readonly, strong) GPBUInt64Array *varintList;
+@property(nonatomic, readonly, strong) GPBUInt32Array *fixed32List;
+@property(nonatomic, readonly, strong) GPBUInt64Array *fixed64List;
+@property(nonatomic, readonly, strong) NSArray *lengthDelimitedList;  // NSData
+@property(nonatomic, readonly, strong) NSArray *groupList;  // GPBUnknownFieldSet
+
+// Only one of these should be used per Field.
+- (void)addVarint:(uint64_t)value;
+- (void)addFixed32:(uint32_t)value;
+- (void)addFixed64:(uint64_t)value;
+- (void)addLengthDelimited:(NSData *)value;
+- (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..c49c0df
--- /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.h"
+
+@implementation GPBUnknownField {
+ @protected
+  int32_t number_;
+  GPBUInt64Array *mutableVarintList_;
+  GPBUInt32Array *mutableFixed32List_;
+  GPBUInt64Array *mutableFixed64List_;
+  NSMutableArray *mutableLengthDelimitedList_;
+  NSMutableArray *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..d785ca1
--- /dev/null
+++ b/objectivec/GPBUnknownFieldSet.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>
+
+@class GPBUnknownField;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GPBUnknownFieldSet : NSObject<NSCopying>
+
+- (BOOL)hasField:(int32_t)number;
+- (nullable GPBUnknownField *)getField:(int32_t)number;
+- (NSUInteger)countOfFields;
+
+- (void)addField:(GPBUnknownField *)field;
+
+// Returns an NSArray of the GPBFields sorted by the field numbers.
+- (NSArray *)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..5b55104
--- /dev/null
+++ b/objectivec/GPBUtilities.h
@@ -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.
+
+#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. lineIndent can be nil if no additional line indent is
+// needed. The comments provide the names according to the ObjC library, they
+// most likely won't exactly match the original .proto file.
+NSString *GPBTextFormatForMessage(GPBMessage *message,
+                                  NSString * __nullable lineIndent);
+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);
+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
+
+NSData *GPBGetMessageBytesField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageBytesField(GPBMessage *self, GPBFieldDescriptor *field, NSData *value);
+
+NSString *GPBGetMessageStringField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageStringField(GPBMessage *self, GPBFieldDescriptor *field, NSString *value);
+
+GPBMessage *GPBGetMessageMessageField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageMessageField(GPBMessage *self, GPBFieldDescriptor *field, GPBMessage *value);
+
+GPBMessage *GPBGetMessageGroupField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageGroupField(GPBMessage *self, GPBFieldDescriptor *field, GPBMessage *value);
+
+BOOL GPBGetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field, BOOL value);
+
+int32_t GPBGetMessageInt32Field(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageInt32Field(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+
+uint32_t GPBGetMessageUInt32Field(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageUInt32Field(GPBMessage *self, GPBFieldDescriptor *field, uint32_t value);
+
+int64_t GPBGetMessageInt64Field(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageInt64Field(GPBMessage *self, GPBFieldDescriptor *field, int64_t value);
+
+uint64_t GPBGetMessageUInt64Field(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageUInt64Field(GPBMessage *self, GPBFieldDescriptor *field, uint64_t value);
+
+float GPBGetMessageFloatField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageFloatField(GPBMessage *self, GPBFieldDescriptor *field, float value);
+
+double GPBGetMessageDoubleField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageDoubleField(GPBMessage *self, GPBFieldDescriptor *field, double value);
+
+// Get/Set the given enum field of a message.  You can only Set values that are
+// members of the enum.  For proto3, when doing a Get, if the value isn't a
+// memeber of the enum, kGPBUnrecognizedEnumeratorValue will be returned. The
+// the functions with "Raw" in the will bypass all checks.
+int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+
+// Repeated Fields
+
+// The object will/should be GPB*Array or NSMutableArray based on the field's
+// type.
+id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field);
+void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array);
+
+// Map Fields
+
+// The object will/should be GPB*Dictionary or NSMutableDictionary based on the
+// field's type.
+id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field);
+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)
+//%GPB_ACCESSOR_SINGLE(UInt32, uint32_t)
+//%GPB_ACCESSOR_SINGLE(Int64, int64_t)
+//%GPB_ACCESSOR_SINGLE(UInt64, uint64_t)
+//%GPB_ACCESSOR_SINGLE(Float, float)
+//%GPB_ACCESSOR_SINGLE(Double, double)
+//%// Get/Set the given enum field of a message.  You can only Set values that are
+//%// members of the enum.  For proto3, when doing a Get, if the value isn't a
+//%// memeber of the enum, kGPBUnrecognizedEnumeratorValue will be returned. The
+//%// the functions with "Raw" in the will bypass all checks.
+//%int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+//%void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+//%int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+//%void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+//%
+//%// Repeated Fields
+//%
+//%// The object will/should be GPB*Array or NSMutableArray based on the field's
+//%// type.
+//%id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field);
+//%void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array);
+//%
+//%// Map Fields
+//%
+//%// The object will/should be GPB*Dictionary or NSMutableDictionary based on the
+//%// field's type.
+//%id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field);
+//%void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, id dictionary);
+//%
+
+//%PDDM-DEFINE GPB_ACCESSOR_SINGLE(NAME, TYPE)
+//%GPB_ACCESSOR_SINGLE_FULL(NAME, TYPE, )
+//%PDDM-DEFINE GPB_ACCESSOR_SINGLE_FULL(NAME, TYPE, TisP)
+//%TYPE TisP##GPBGetMessage##NAME##Field(GPBMessage *self, GPBFieldDescriptor *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..d4d6471
--- /dev/null
+++ b/objectivec/GPBUtilities.m
@@ -0,0 +1,1710 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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,
+                        uint32_t fieldNumberNotToClear) {
+  int32_t hasIndex = oneof->oneofDescription_->index;
+  uint32_t fieldNumberSet = GPBGetHasOneof(self, hasIndex);
+  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, hasIndex, 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) {
+//%    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+//%  }
+//%  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) {
+      GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+    }
+    // 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;
+  }
+
+  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);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Bool, BOOL)
+// This block of code is generated, do not edit it directly.
+
+BOOL GPBGetMessageBoolField(GPBMessage *self,
+                            GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    BOOL *typePtr = (BOOL *)&storage[field->description_->offset];
+    return *typePtr;
+  } 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) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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_;
+  BOOL *typePtr = (BOOL *)&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 != (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) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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) {
+    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+  }
+  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 (7 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..cac551f
--- /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,
+                        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..6b34b9b
--- /dev/null
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
@@ -0,0 +1,950 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 47;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; };
+		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 */; };
+		8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.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>"; };
+		8B42494B1A92A16600BC1EC6 /* descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = descriptor.proto; path = ../src/google/protobuf/descriptor.proto; 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>"; };
+		8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Descriptor.pbobjc.h; path = google/protobuf/Descriptor.pbobjc.h; sourceTree = SOURCE_ROOT; };
+		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>"; };
+		8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Descriptor.pbobjc.m; path = google/protobuf/Descriptor.pbobjc.m; sourceTree = SOURCE_ROOT; };
+		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>"; };
+		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 */,
+				8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */,
+				8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */,
+				8B42494B1A92A16600BC1EC6 /* descriptor.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 = (
+				7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */,
+				51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */,
+				7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */,
+				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 = (
+				2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */,
+				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 */,
+				8B96157514CA019D00A2AC0B /* Descriptor.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..e9d3fc9
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
@@ -0,0 +1,1123 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 47;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; };
+		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 */; };
+		8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.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>"; };
+		8B4249491A92A0BA00BC1EC6 /* descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = descriptor.proto; path = ../src/google/protobuf/descriptor.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>"; };
+		8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Descriptor.pbobjc.m; path = google/protobuf/Descriptor.pbobjc.m; sourceTree = SOURCE_ROOT; };
+		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>"; };
+		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>"; };
+		F4E675BA1B21D1440054530B /* Descriptor.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Descriptor.pbobjc.h; path = google/protobuf/Descriptor.pbobjc.h; 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 */,
+				F4E675BA1B21D1440054530B /* Descriptor.pbobjc.h */,
+				8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */,
+				8B4249491A92A0BA00BC1EC6 /* descriptor.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 = (
+				7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */,
+				51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */,
+				7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */,
+				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 = (
+				2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */,
+				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 */,
+				8B96157514CA019D00A2AC0B /* Descriptor.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..d040886
--- /dev/null
+++ b/objectivec/Tests/GPBARCUnittestProtos.m
@@ -0,0 +1,56 @@
+#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.
+
+#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..b0e39d2
--- /dev/null
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -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.
+
+#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];
+  TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
+                                                extensionRegistry:nil
+                                                            error:NULL];
+  XCTAssertNotNil(message);
+  // Make sure we can read string properties twice without crashing.
+  XCTAssertEqual([message.defaultString length], (NSUInteger)0);
+  XCTAssertEqualObjects(@"", message.defaultString);
+}
+
+@end
diff --git a/objectivec/Tests/GPBCodedOuputStreamTests.m b/objectivec/Tests/GPBCodedOuputStreamTests.m
new file mode 100644
index 0000000..77d8803
--- /dev/null
+++ b/objectivec/Tests/GPBCodedOuputStreamTests.m
@@ -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.
+
+#import "GPBTestUtilities.h"
+
+#import "GPBCodedOutputStream.h"
+#import "GPBCodedInputStream.h"
+#import "GPBUtilities_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+
+@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..ccdbb64
--- /dev/null
+++ b/objectivec/Tests/GPBDescriptorTests.m
@@ -0,0 +1,232 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)testEnumDescriptorLookup {
+  GPBDescriptor *descriptor = [TestAllTypes descriptor];
+  GPBEnumDescriptor *enumDescriptor =
+      [descriptor enumWithName:@"TestAllTypes_NestedEnum"];
+  XCTAssertNotNil(enumDescriptor);
+
+  // Descriptor cannot find foreign or imported enums.
+  enumDescriptor = [descriptor enumWithName:@"ForeignEnumEnum"];
+  XCTAssertNil(enumDescriptor);
+  enumDescriptor = [descriptor enumWithName:@"ImportEnumEnum"];
+  XCTAssertNil(enumDescriptor);
+}
+
+- (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..8b1900f
--- /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, id, @"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 *dict = [[GPBBoolObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:YES]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, id aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolObjectDictionary *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, id aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const id kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary *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));
+  id *seenObjects = malloc(2 * sizeof(id));
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, id 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, id 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 id kObjects1[] = { @"abc", @"def" };
+  const id kObjects2[] = { @"def", @"abc" };
+  const id kObjects3[] = { @"def" };
+  GPBBoolObjectDictionary *dict1 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolObjectDictionary *dict1prime =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolObjectDictionary *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolObjectDictionary *dict3 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolObjectDictionary *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 id kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolObjectDictionary *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 id kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolObjectDictionary *dict2 =
+      [GPBBoolObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setObject:@"abc" forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const id kObjects[] = { @"def" };
+  GPBBoolObjectDictionary *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 id kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary *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 id kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary *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 id kObjects2[] = { @"def", @"abc" };
+  GPBBoolObjectDictionary *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..21d3f07
--- /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 *dict = [[GPBInt32ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:11]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, id aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32ObjectDictionary *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, id aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const id kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBInt32ObjectDictionary *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));
+  id *seenObjects = malloc(3 * sizeof(id));
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, id 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, id 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 id kObjects1[] = { @"abc", @"def", @"ghi" };
+  const id kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const id kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary *dict1 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32ObjectDictionary *dict1prime =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32ObjectDictionary *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32ObjectDictionary *dict3 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32ObjectDictionary *dict2 =
+      [GPBInt32ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32ObjectDictionary *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 id kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary *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 id kObjects2[] = { @"ghi", @"abc" };
+  GPBInt32ObjectDictionary *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..27f77f2
--- /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 *dict = [[GPBInt64ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:21LL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, id aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64ObjectDictionary *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, id aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const id kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBInt64ObjectDictionary *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));
+  id *seenObjects = malloc(3 * sizeof(id));
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, id 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, id 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 id kObjects1[] = { @"abc", @"def", @"ghi" };
+  const id kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const id kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary *dict1 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64ObjectDictionary *dict1prime =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64ObjectDictionary *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64ObjectDictionary *dict3 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64ObjectDictionary *dict2 =
+      [GPBInt64ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64ObjectDictionary *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 id kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary *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 id kObjects2[] = { @"ghi", @"abc" };
+  GPBInt64ObjectDictionary *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..c7c5765
--- /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 *dict = [[GPBUInt32ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:1U]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, id aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32ObjectDictionary *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, id aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const id kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBUInt32ObjectDictionary *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));
+  id *seenObjects = malloc(3 * sizeof(id));
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, id 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, id 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 id kObjects1[] = { @"abc", @"def", @"ghi" };
+  const id kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const id kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary *dict1 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32ObjectDictionary *dict1prime =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32ObjectDictionary *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32ObjectDictionary *dict3 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32ObjectDictionary *dict2 =
+      [GPBUInt32ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32ObjectDictionary *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 id kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary *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 id kObjects2[] = { @"ghi", @"abc" };
+  GPBUInt32ObjectDictionary *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..b64d3a9
--- /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 *dict = [[GPBUInt64ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:31ULL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, id aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64ObjectDictionary *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, id aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const id kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBUInt64ObjectDictionary *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));
+  id *seenObjects = malloc(3 * sizeof(id));
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, id 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, id 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 id kObjects1[] = { @"abc", @"def", @"ghi" };
+  const id kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const id kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary *dict1 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64ObjectDictionary *dict1prime =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64ObjectDictionary *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64ObjectDictionary *dict3 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64ObjectDictionary *dict2 =
+      [GPBUInt64ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64ObjectDictionary *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 id kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary *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 id kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary *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 id kObjects2[] = { @"ghi", @"abc" };
+  GPBUInt64ObjectDictionary *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..ada93c6
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests.pddm
@@ -0,0 +1,1040 @@
+// 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, id, @"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 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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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);
+//%
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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 };
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *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..7b37ca9
--- /dev/null
+++ b/objectivec/Tests/GPBMessageTests.m
@@ -0,0 +1,1932 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)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);
+}
+
+@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..50c4dfa
--- /dev/null
+++ b/objectivec/Tests/GPBUnittestProtos.m
@@ -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.
+
+// Collects all the compiled protos into one file and compiles them to make sure
+// the compiler is generating valid code.
+
+#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..3bb9276
--- /dev/null
+++ b/objectivec/Tests/unittest_objc.proto
@@ -0,0 +1,391 @@
+// 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;
+}
+
+// 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;
+}
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_descriptors_proto.sh b/objectivec/generate_descriptors_proto.sh
new file mode 100755
index 0000000..84ba073
--- /dev/null
+++ b/objectivec/generate_descriptors_proto.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# Run this script to regenerate descriptor.pbobjc.{h,m} after the protocol
+# compiler changes.
+
+# 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.
+
+set -eu
+
+readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
+readonly ProtoRootDir="${ScriptDir}/.."
+
+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/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)
+
+./protoc --objc_out="${ProtoRootDir}/objectivec" ${RUNTIME_PROTO_FILES[@]}
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
new file mode 100644
index 0000000..9866b5b
--- /dev/null
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -0,0 +1,97 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBAnyRoot
+
+@interface GPBAnyRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBAny
+
+typedef GPB_ENUM(GPBAny_FieldNumber) {
+  GPBAny_FieldNumber_TypeURL = 1,
+  GPBAny_FieldNumber_Value = 2,
+};
+
+// `Any` contains an arbitrary serialized message along with a URL
+// that describes the type of the serialized message.
+//
+//
+// 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 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`).
+// * 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 valid serialized data of the above specified type.
+@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+// @@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..b41102a
--- /dev/null
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -0,0 +1,99 @@
+// 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 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",
+        .number = GPBAny_FieldNumber_TypeURL,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBAny__storage_, typeURL),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "value",
+        .number = GPBAny_FieldNumber_Value,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBytes,
+        .offset = offsetof(GPBAny__storage_, value),
+        .defaultValue.valueData = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    const char *extraTextFormatInfo = NULL;
+#else
+    static const char *extraTextFormatInfo = "\001\001\004\241!!\000";
+#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBAny class]
+                                     rootClass:[GPBAnyRoot class]
+                                          file:GPBAnyRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBAny__storage_)
+                                    wireFormat:NO
+                           extraTextFormatInfo:extraTextFormatInfo];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..c3cf8e9
--- /dev/null
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -0,0 +1,241 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBSourceContext;
+GPB_ENUM_FWD_DECLARE(GPBSyntax);
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBApiRoot
+
+@interface GPBApiRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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.
+// |methodsArray| contains |GPBMethod|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodsArray;
+@property(nonatomic, readonly) NSUInteger methodsArray_Count;
+
+// Any metadata attached to the API.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@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) BOOL hasSourceContext;
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
+
+// Included APIs. See [Mixin][].
+// |mixinsArray| contains |GPBMixin|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *mixinsArray;
+@property(nonatomic, readonly) NSUInteger mixinsArray_Count;
+
+// The source syntax of the service.
+@property(nonatomic, readwrite) enum GPBSyntax syntax;
+
+@end
+
+int32_t GPBApi_Syntax_RawValue(GPBApi *message);
+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.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+// The source syntax of this method.
+@property(nonatomic, readwrite) enum GPBSyntax syntax;
+
+@end
+
+int32_t GPBMethod_Syntax_RawValue(GPBMethod *message);
+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
+
+// @@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..d964ff4
--- /dev/null
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -0,0 +1,396 @@
+// 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 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",
+        .number = GPBApi_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBApi__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "methodsArray",
+        .number = GPBApi_FieldNumber_MethodsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBApi__storage_, methodsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBApi_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBApi__storage_, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "version",
+        .number = GPBApi_FieldNumber_Version,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBApi__storage_, version),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceContext",
+        .number = GPBApi_FieldNumber_SourceContext,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBApi__storage_, sourceContext),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "mixinsArray",
+        .number = GPBApi_FieldNumber_MixinsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBApi__storage_, mixinsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "syntax",
+        .number = GPBApi_FieldNumber_Syntax,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBApi__storage_, syntax),
+        .defaultValue.valueEnum = GPBSyntax_SyntaxProto2,
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBApi class]
+                                     rootClass:[GPBApiRoot class]
+                                          file:GPBApiRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBApi__storage_)
+                                    wireFormat:NO];
+    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];
+  BOOL requestStreaming;
+  BOOL responseStreaming;
+  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",
+        .number = GPBMethod_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMethod__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "requestTypeURL",
+        .number = GPBMethod_FieldNumber_RequestTypeURL,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMethod__storage_, requestTypeURL),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "requestStreaming",
+        .number = GPBMethod_FieldNumber_RequestStreaming,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMethod__storage_, requestStreaming),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "responseTypeURL",
+        .number = GPBMethod_FieldNumber_ResponseTypeURL,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMethod__storage_, responseTypeURL),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "responseStreaming",
+        .number = GPBMethod_FieldNumber_ResponseStreaming,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMethod__storage_, responseStreaming),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBMethod_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBMethod__storage_, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "syntax",
+        .number = GPBMethod_FieldNumber_Syntax,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBMethod__storage_, syntax),
+        .defaultValue.valueEnum = GPBSyntax_SyntaxProto2,
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+    };
+#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    const char *extraTextFormatInfo = NULL;
+#else
+    static const char *extraTextFormatInfo = "\002\002\007\244\241!!\000\004\010\244\241!!\000";
+#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMethod class]
+                                     rootClass:[GPBApiRoot class]
+                                          file:GPBApiRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBMethod__storage_)
+                                    wireFormat:NO
+                           extraTextFormatInfo:extraTextFormatInfo];
+    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",
+        .number = GPBMixin_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMixin__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "root",
+        .number = GPBMixin_FieldNumber_Root,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMixin__storage_, root),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMixin class]
+                                     rootClass:[GPBApiRoot class]
+                                          file:GPBApiRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBMixin__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.h b/objectivec/google/protobuf/Descriptor.pbobjc.h
new file mode 100644
index 0000000..9c43cfd
--- /dev/null
+++ b/objectivec/google/protobuf/Descriptor.pbobjc.h
@@ -0,0 +1,1212 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBEnumOptions;
+@class GPBEnumValueOptions;
+@class GPBFieldOptions;
+@class GPBFileOptions;
+@class GPBMessageOptions;
+@class GPBMethodOptions;
+@class GPBServiceOptions;
+@class GPBSourceCodeInfo;
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - Enum GPBFieldDescriptorProto_Type
+
+typedef GPB_ENUM(GPBFieldDescriptorProto_Type) {
+  // 0 is reserved for errors.
+  // Order is weird for historical reasons.
+  GPBFieldDescriptorProto_Type_TypeDouble = 1,
+  GPBFieldDescriptorProto_Type_TypeFloat = 2,
+
+  // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+  // negative values are likely.
+  GPBFieldDescriptorProto_Type_TypeInt64 = 3,
+  GPBFieldDescriptorProto_Type_TypeUint64 = 4,
+
+  // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+  // negative values are likely.
+  GPBFieldDescriptorProto_Type_TypeInt32 = 5,
+  GPBFieldDescriptorProto_Type_TypeFixed64 = 6,
+  GPBFieldDescriptorProto_Type_TypeFixed32 = 7,
+  GPBFieldDescriptorProto_Type_TypeBool = 8,
+  GPBFieldDescriptorProto_Type_TypeString = 9,
+
+  // Tag-delimited aggregate.
+  GPBFieldDescriptorProto_Type_TypeGroup = 10,
+
+  // Length-delimited aggregate.
+  GPBFieldDescriptorProto_Type_TypeMessage = 11,
+
+  // New in version 2.
+  GPBFieldDescriptorProto_Type_TypeBytes = 12,
+  GPBFieldDescriptorProto_Type_TypeUint32 = 13,
+  GPBFieldDescriptorProto_Type_TypeEnum = 14,
+  GPBFieldDescriptorProto_Type_TypeSfixed32 = 15,
+  GPBFieldDescriptorProto_Type_TypeSfixed64 = 16,
+
+  // Uses ZigZag encoding.
+  GPBFieldDescriptorProto_Type_TypeSint32 = 17,
+
+  // Uses ZigZag encoding.
+  GPBFieldDescriptorProto_Type_TypeSint64 = 18,
+};
+
+GPBEnumDescriptor *GPBFieldDescriptorProto_Type_EnumDescriptor(void);
+
+BOOL GPBFieldDescriptorProto_Type_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBFieldDescriptorProto_Label
+
+typedef GPB_ENUM(GPBFieldDescriptorProto_Label) {
+  // 0 is reserved for errors
+  GPBFieldDescriptorProto_Label_LabelOptional = 1,
+  GPBFieldDescriptorProto_Label_LabelRequired = 2,
+
+  // TODO(sanjay): Should we add LABEL_MAP?
+  GPBFieldDescriptorProto_Label_LabelRepeated = 3,
+};
+
+GPBEnumDescriptor *GPBFieldDescriptorProto_Label_EnumDescriptor(void);
+
+BOOL GPBFieldDescriptorProto_Label_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBFileOptions_OptimizeMode
+
+// Generated classes can be optimized for speed or code size.
+typedef GPB_ENUM(GPBFileOptions_OptimizeMode) {
+  // Generate complete code for parsing, serialization,
+  GPBFileOptions_OptimizeMode_Speed = 1,
+
+  // etc.
+  GPBFileOptions_OptimizeMode_CodeSize = 2,
+
+  // Generate code using MessageLite and the lite runtime.
+  GPBFileOptions_OptimizeMode_LiteRuntime = 3,
+};
+
+GPBEnumDescriptor *GPBFileOptions_OptimizeMode_EnumDescriptor(void);
+
+BOOL GPBFileOptions_OptimizeMode_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBFieldOptions_CType
+
+typedef GPB_ENUM(GPBFieldOptions_CType) {
+  // Default mode.
+  GPBFieldOptions_CType_String = 0,
+  GPBFieldOptions_CType_Cord = 1,
+  GPBFieldOptions_CType_StringPiece = 2,
+};
+
+GPBEnumDescriptor *GPBFieldOptions_CType_EnumDescriptor(void);
+
+BOOL GPBFieldOptions_CType_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBFieldOptions_JSType
+
+typedef GPB_ENUM(GPBFieldOptions_JSType) {
+  // Use the default type.
+  GPBFieldOptions_JSType_JsNormal = 0,
+
+  // Use JavaScript strings.
+  GPBFieldOptions_JSType_JsString = 1,
+
+  // Use JavaScript numbers.
+  GPBFieldOptions_JSType_JsNumber = 2,
+};
+
+GPBEnumDescriptor *GPBFieldOptions_JSType_EnumDescriptor(void);
+
+BOOL GPBFieldOptions_JSType_IsValidValue(int32_t value);
+
+#pragma mark - GPBDescriptorRoot
+
+@interface GPBDescriptorRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBFileDescriptorSet
+
+typedef GPB_ENUM(GPBFileDescriptorSet_FieldNumber) {
+  GPBFileDescriptorSet_FieldNumber_FileArray = 1,
+};
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+@interface GPBFileDescriptorSet : GPBMessage
+
+// |fileArray| contains |GPBFileDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fileArray;
+@property(nonatomic, readonly) NSUInteger fileArray_Count;
+
+@end
+
+#pragma mark - GPBFileDescriptorProto
+
+typedef GPB_ENUM(GPBFileDescriptorProto_FieldNumber) {
+  GPBFileDescriptorProto_FieldNumber_Name = 1,
+  GPBFileDescriptorProto_FieldNumber_Package = 2,
+  GPBFileDescriptorProto_FieldNumber_DependencyArray = 3,
+  GPBFileDescriptorProto_FieldNumber_MessageTypeArray = 4,
+  GPBFileDescriptorProto_FieldNumber_EnumTypeArray = 5,
+  GPBFileDescriptorProto_FieldNumber_ServiceArray = 6,
+  GPBFileDescriptorProto_FieldNumber_ExtensionArray = 7,
+  GPBFileDescriptorProto_FieldNumber_Options = 8,
+  GPBFileDescriptorProto_FieldNumber_SourceCodeInfo = 9,
+  GPBFileDescriptorProto_FieldNumber_PublicDependencyArray = 10,
+  GPBFileDescriptorProto_FieldNumber_WeakDependencyArray = 11,
+  GPBFileDescriptorProto_FieldNumber_Syntax = 12,
+};
+
+// Describes a complete .proto file.
+@interface GPBFileDescriptorProto : GPBMessage
+
+// file name, relative to root of source tree
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+// e.g. "foo", "foo.bar", etc.
+@property(nonatomic, readwrite) BOOL hasPackage;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *package;
+
+// Names of files imported by this file.
+// |dependencyArray| contains |NSString|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *dependencyArray;
+@property(nonatomic, readonly) NSUInteger dependencyArray_Count;
+
+// Indexes of the public imported files in the dependency list above.
+@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *publicDependencyArray;
+@property(nonatomic, readonly) NSUInteger publicDependencyArray_Count;
+
+// Indexes of the weak imported files in the dependency list.
+// For Google-internal migration only. Do not use.
+@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *weakDependencyArray;
+@property(nonatomic, readonly) NSUInteger weakDependencyArray_Count;
+
+// All top-level definitions in this file.
+// |messageTypeArray| contains |GPBDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *messageTypeArray;
+@property(nonatomic, readonly) NSUInteger messageTypeArray_Count;
+
+// |enumTypeArray| contains |GPBEnumDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumTypeArray;
+@property(nonatomic, readonly) NSUInteger enumTypeArray_Count;
+
+// |serviceArray| contains |GPBServiceDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *serviceArray;
+@property(nonatomic, readonly) NSUInteger serviceArray_Count;
+
+// |extensionArray| contains |GPBFieldDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionArray;
+@property(nonatomic, readonly) NSUInteger extensionArray_Count;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBFileOptions *options;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasSourceCodeInfo;
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceCodeInfo *sourceCodeInfo;
+
+// The syntax of the proto file.
+// The supported values are "proto2" and "proto3".
+@property(nonatomic, readwrite) BOOL hasSyntax;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *syntax;
+
+@end
+
+#pragma mark - GPBDescriptorProto
+
+typedef GPB_ENUM(GPBDescriptorProto_FieldNumber) {
+  GPBDescriptorProto_FieldNumber_Name = 1,
+  GPBDescriptorProto_FieldNumber_FieldArray = 2,
+  GPBDescriptorProto_FieldNumber_NestedTypeArray = 3,
+  GPBDescriptorProto_FieldNumber_EnumTypeArray = 4,
+  GPBDescriptorProto_FieldNumber_ExtensionRangeArray = 5,
+  GPBDescriptorProto_FieldNumber_ExtensionArray = 6,
+  GPBDescriptorProto_FieldNumber_Options = 7,
+  GPBDescriptorProto_FieldNumber_OneofDeclArray = 8,
+  GPBDescriptorProto_FieldNumber_ReservedRangeArray = 9,
+  GPBDescriptorProto_FieldNumber_ReservedNameArray = 10,
+};
+
+// Describes a message type.
+@interface GPBDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+// |fieldArray| contains |GPBFieldDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldArray;
+@property(nonatomic, readonly) NSUInteger fieldArray_Count;
+
+// |extensionArray| contains |GPBFieldDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionArray;
+@property(nonatomic, readonly) NSUInteger extensionArray_Count;
+
+// |nestedTypeArray| contains |GPBDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nestedTypeArray;
+@property(nonatomic, readonly) NSUInteger nestedTypeArray_Count;
+
+// |enumTypeArray| contains |GPBEnumDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumTypeArray;
+@property(nonatomic, readonly) NSUInteger enumTypeArray_Count;
+
+// |extensionRangeArray| contains |GPBDescriptorProto_ExtensionRange|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionRangeArray;
+@property(nonatomic, readonly) NSUInteger extensionRangeArray_Count;
+
+// |oneofDeclArray| contains |GPBOneofDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofDeclArray;
+@property(nonatomic, readonly) NSUInteger oneofDeclArray_Count;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBMessageOptions *options;
+
+// |reservedRangeArray| contains |GPBDescriptorProto_ReservedRange|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *reservedRangeArray;
+@property(nonatomic, readonly) NSUInteger reservedRangeArray_Count;
+
+// Reserved field names, which may not be used by fields in the same message.
+// A given name may only be reserved once.
+// |reservedNameArray| contains |NSString|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *reservedNameArray;
+@property(nonatomic, readonly) NSUInteger reservedNameArray_Count;
+
+@end
+
+#pragma mark - GPBDescriptorProto_ExtensionRange
+
+typedef GPB_ENUM(GPBDescriptorProto_ExtensionRange_FieldNumber) {
+  GPBDescriptorProto_ExtensionRange_FieldNumber_Start = 1,
+  GPBDescriptorProto_ExtensionRange_FieldNumber_End = 2,
+};
+
+@interface GPBDescriptorProto_ExtensionRange : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasStart;
+@property(nonatomic, readwrite) int32_t start;
+
+@property(nonatomic, readwrite) BOOL hasEnd;
+@property(nonatomic, readwrite) int32_t end;
+
+@end
+
+#pragma mark - GPBDescriptorProto_ReservedRange
+
+typedef GPB_ENUM(GPBDescriptorProto_ReservedRange_FieldNumber) {
+  GPBDescriptorProto_ReservedRange_FieldNumber_Start = 1,
+  GPBDescriptorProto_ReservedRange_FieldNumber_End = 2,
+};
+
+// 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.
+@interface GPBDescriptorProto_ReservedRange : GPBMessage
+
+// Inclusive.
+@property(nonatomic, readwrite) BOOL hasStart;
+@property(nonatomic, readwrite) int32_t start;
+
+// Exclusive.
+@property(nonatomic, readwrite) BOOL hasEnd;
+@property(nonatomic, readwrite) int32_t end;
+
+@end
+
+#pragma mark - GPBFieldDescriptorProto
+
+typedef GPB_ENUM(GPBFieldDescriptorProto_FieldNumber) {
+  GPBFieldDescriptorProto_FieldNumber_Name = 1,
+  GPBFieldDescriptorProto_FieldNumber_Extendee = 2,
+  GPBFieldDescriptorProto_FieldNumber_Number = 3,
+  GPBFieldDescriptorProto_FieldNumber_Label = 4,
+  GPBFieldDescriptorProto_FieldNumber_Type = 5,
+  GPBFieldDescriptorProto_FieldNumber_TypeName = 6,
+  GPBFieldDescriptorProto_FieldNumber_DefaultValue = 7,
+  GPBFieldDescriptorProto_FieldNumber_Options = 8,
+  GPBFieldDescriptorProto_FieldNumber_OneofIndex = 9,
+  GPBFieldDescriptorProto_FieldNumber_JsonName = 10,
+};
+
+// Describes a field within a message.
+@interface GPBFieldDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+@property(nonatomic, readwrite) BOOL hasNumber;
+@property(nonatomic, readwrite) int32_t number;
+
+@property(nonatomic, readwrite) BOOL hasLabel;
+@property(nonatomic, readwrite) GPBFieldDescriptorProto_Label label;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasType;
+@property(nonatomic, readwrite) GPBFieldDescriptorProto_Type type;
+
+// 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).
+@property(nonatomic, readwrite) BOOL hasTypeName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *typeName;
+
+// For extensions, this is the name of the type being extended.  It is
+// resolved in the same manner as type_name.
+@property(nonatomic, readwrite) BOOL hasExtendee;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *extendee;
+
+// 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?
+@property(nonatomic, readwrite) BOOL hasDefaultValue;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue;
+
+// If set, gives the index of a oneof in the containing type's oneof_decl
+// list.  This field is a member of that oneof.
+@property(nonatomic, readwrite) BOOL hasOneofIndex;
+@property(nonatomic, readwrite) int32_t oneofIndex;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasJsonName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBFieldOptions *options;
+
+@end
+
+#pragma mark - GPBOneofDescriptorProto
+
+typedef GPB_ENUM(GPBOneofDescriptorProto_FieldNumber) {
+  GPBOneofDescriptorProto_FieldNumber_Name = 1,
+};
+
+// Describes a oneof.
+@interface GPBOneofDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+@end
+
+#pragma mark - GPBEnumDescriptorProto
+
+typedef GPB_ENUM(GPBEnumDescriptorProto_FieldNumber) {
+  GPBEnumDescriptorProto_FieldNumber_Name = 1,
+  GPBEnumDescriptorProto_FieldNumber_ValueArray = 2,
+  GPBEnumDescriptorProto_FieldNumber_Options = 3,
+};
+
+// Describes an enum type.
+@interface GPBEnumDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+// |valueArray| contains |GPBEnumValueDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valueArray;
+@property(nonatomic, readonly) NSUInteger valueArray_Count;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBEnumOptions *options;
+
+@end
+
+#pragma mark - GPBEnumValueDescriptorProto
+
+typedef GPB_ENUM(GPBEnumValueDescriptorProto_FieldNumber) {
+  GPBEnumValueDescriptorProto_FieldNumber_Name = 1,
+  GPBEnumValueDescriptorProto_FieldNumber_Number = 2,
+  GPBEnumValueDescriptorProto_FieldNumber_Options = 3,
+};
+
+// Describes a value within an enum.
+@interface GPBEnumValueDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+@property(nonatomic, readwrite) BOOL hasNumber;
+@property(nonatomic, readwrite) int32_t number;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBEnumValueOptions *options;
+
+@end
+
+#pragma mark - GPBServiceDescriptorProto
+
+typedef GPB_ENUM(GPBServiceDescriptorProto_FieldNumber) {
+  GPBServiceDescriptorProto_FieldNumber_Name = 1,
+  GPBServiceDescriptorProto_FieldNumber_MethodArray = 2,
+  GPBServiceDescriptorProto_FieldNumber_Options = 3,
+};
+
+// Describes a service.
+@interface GPBServiceDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+// |methodArray| contains |GPBMethodDescriptorProto|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodArray;
+@property(nonatomic, readonly) NSUInteger methodArray_Count;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBServiceOptions *options;
+
+@end
+
+#pragma mark - GPBMethodDescriptorProto
+
+typedef GPB_ENUM(GPBMethodDescriptorProto_FieldNumber) {
+  GPBMethodDescriptorProto_FieldNumber_Name = 1,
+  GPBMethodDescriptorProto_FieldNumber_InputType = 2,
+  GPBMethodDescriptorProto_FieldNumber_OutputType = 3,
+  GPBMethodDescriptorProto_FieldNumber_Options = 4,
+  GPBMethodDescriptorProto_FieldNumber_ClientStreaming = 5,
+  GPBMethodDescriptorProto_FieldNumber_ServerStreaming = 6,
+};
+
+// Describes a method of a service.
+@interface GPBMethodDescriptorProto : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+// Input and output type names.  These are resolved in the same way as
+// FieldDescriptorProto.type_name, but must refer to a message type.
+@property(nonatomic, readwrite) BOOL hasInputType;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *inputType;
+
+@property(nonatomic, readwrite) BOOL hasOutputType;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *outputType;
+
+@property(nonatomic, readwrite) BOOL hasOptions;
+@property(nonatomic, readwrite, strong, null_resettable) GPBMethodOptions *options;
+
+// Identifies if client streams multiple client messages
+@property(nonatomic, readwrite) BOOL hasClientStreaming;
+@property(nonatomic, readwrite) BOOL clientStreaming;
+
+// Identifies if server streams multiple server messages
+@property(nonatomic, readwrite) BOOL hasServerStreaming;
+@property(nonatomic, readwrite) BOOL serverStreaming;
+
+@end
+
+#pragma mark - GPBFileOptions
+
+typedef GPB_ENUM(GPBFileOptions_FieldNumber) {
+  GPBFileOptions_FieldNumber_JavaPackage = 1,
+  GPBFileOptions_FieldNumber_JavaOuterClassname = 8,
+  GPBFileOptions_FieldNumber_OptimizeFor = 9,
+  GPBFileOptions_FieldNumber_JavaMultipleFiles = 10,
+  GPBFileOptions_FieldNumber_GoPackage = 11,
+  GPBFileOptions_FieldNumber_CcGenericServices = 16,
+  GPBFileOptions_FieldNumber_JavaGenericServices = 17,
+  GPBFileOptions_FieldNumber_PyGenericServices = 18,
+  GPBFileOptions_FieldNumber_JavaGenerateEqualsAndHash = 20,
+  GPBFileOptions_FieldNumber_Deprecated = 23,
+  GPBFileOptions_FieldNumber_JavaStringCheckUtf8 = 27,
+  GPBFileOptions_FieldNumber_CcEnableArenas = 31,
+  GPBFileOptions_FieldNumber_ObjcClassPrefix = 36,
+  GPBFileOptions_FieldNumber_CsharpNamespace = 37,
+  GPBFileOptions_FieldNumber_JavananoUseDeprecatedPackage = 38,
+  GPBFileOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBFileOptions : GPBMessage
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasJavaPackage;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *javaPackage;
+
+// 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).
+@property(nonatomic, readwrite) BOOL hasJavaOuterClassname;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *javaOuterClassname;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasJavaMultipleFiles;
+@property(nonatomic, readwrite) BOOL javaMultipleFiles;
+
+// 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.)
+@property(nonatomic, readwrite) BOOL hasJavaGenerateEqualsAndHash;
+@property(nonatomic, readwrite) BOOL javaGenerateEqualsAndHash;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasJavaStringCheckUtf8;
+@property(nonatomic, readwrite) BOOL javaStringCheckUtf8;
+
+@property(nonatomic, readwrite) BOOL hasOptimizeFor;
+@property(nonatomic, readwrite) GPBFileOptions_OptimizeMode optimizeFor;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasGoPackage;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *goPackage;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasCcGenericServices;
+@property(nonatomic, readwrite) BOOL ccGenericServices;
+
+@property(nonatomic, readwrite) BOOL hasJavaGenericServices;
+@property(nonatomic, readwrite) BOOL javaGenericServices;
+
+@property(nonatomic, readwrite) BOOL hasPyGenericServices;
+@property(nonatomic, readwrite) BOOL pyGenericServices;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// Enables the use of arenas for the proto messages in this file. This applies
+// only to generated classes for C++.
+@property(nonatomic, readwrite) BOOL hasCcEnableArenas;
+@property(nonatomic, readwrite) BOOL ccEnableArenas;
+
+// Sets the objective c class prefix which is prepended to all objective c
+// generated classes from this .proto. There is no default.
+@property(nonatomic, readwrite) BOOL hasObjcClassPrefix;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *objcClassPrefix;
+
+// Namespace for generated classes; defaults to the package.
+@property(nonatomic, readwrite) BOOL hasCsharpNamespace;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *csharpNamespace;
+
+// Whether the nano proto compiler should generate in the deprecated non-nano
+// suffixed package.
+@property(nonatomic, readwrite) BOOL hasJavananoUseDeprecatedPackage;
+@property(nonatomic, readwrite) BOOL javananoUseDeprecatedPackage;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBMessageOptions
+
+typedef GPB_ENUM(GPBMessageOptions_FieldNumber) {
+  GPBMessageOptions_FieldNumber_MessageSetWireFormat = 1,
+  GPBMessageOptions_FieldNumber_NoStandardDescriptorAccessor = 2,
+  GPBMessageOptions_FieldNumber_Deprecated = 3,
+  GPBMessageOptions_FieldNumber_MapEntry = 7,
+  GPBMessageOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBMessageOptions : GPBMessage
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasMessageSetWireFormat;
+@property(nonatomic, readwrite) BOOL messageSetWireFormat;
+
+// 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".
+@property(nonatomic, readwrite) BOOL hasNoStandardDescriptorAccessor;
+@property(nonatomic, readwrite) BOOL noStandardDescriptorAccessor;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasMapEntry;
+@property(nonatomic, readwrite) BOOL mapEntry;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBFieldOptions
+
+typedef GPB_ENUM(GPBFieldOptions_FieldNumber) {
+  GPBFieldOptions_FieldNumber_Ctype = 1,
+  GPBFieldOptions_FieldNumber_Packed = 2,
+  GPBFieldOptions_FieldNumber_Deprecated = 3,
+  GPBFieldOptions_FieldNumber_Lazy = 5,
+  GPBFieldOptions_FieldNumber_Jstype = 6,
+  GPBFieldOptions_FieldNumber_Weak = 10,
+  GPBFieldOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBFieldOptions : GPBMessage
+
+// 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!
+@property(nonatomic, readwrite) BOOL hasCtype;
+@property(nonatomic, readwrite) GPBFieldOptions_CType ctype;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasPacked;
+@property(nonatomic, readwrite) BOOL packed;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasJstype;
+@property(nonatomic, readwrite) GPBFieldOptions_JSType jstype;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasLazy;
+@property(nonatomic, readwrite) BOOL lazy;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// For Google-internal migration only. Do not use.
+@property(nonatomic, readwrite) BOOL hasWeak;
+@property(nonatomic, readwrite) BOOL weak;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBEnumOptions
+
+typedef GPB_ENUM(GPBEnumOptions_FieldNumber) {
+  GPBEnumOptions_FieldNumber_AllowAlias = 2,
+  GPBEnumOptions_FieldNumber_Deprecated = 3,
+  GPBEnumOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBEnumOptions : GPBMessage
+
+// Set this option to true to allow mapping different tag names to the same
+// value.
+@property(nonatomic, readwrite) BOOL hasAllowAlias;
+@property(nonatomic, readwrite) BOOL allowAlias;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBEnumValueOptions
+
+typedef GPB_ENUM(GPBEnumValueOptions_FieldNumber) {
+  GPBEnumValueOptions_FieldNumber_Deprecated = 1,
+  GPBEnumValueOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBEnumValueOptions : GPBMessage
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBServiceOptions
+
+typedef GPB_ENUM(GPBServiceOptions_FieldNumber) {
+  GPBServiceOptions_FieldNumber_Deprecated = 33,
+  GPBServiceOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBServiceOptions : GPBMessage
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBMethodOptions
+
+typedef GPB_ENUM(GPBMethodOptions_FieldNumber) {
+  GPBMethodOptions_FieldNumber_Deprecated = 33,
+  GPBMethodOptions_FieldNumber_UninterpretedOptionArray = 999,
+};
+
+@interface GPBMethodOptions : GPBMessage
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasDeprecated;
+@property(nonatomic, readwrite) BOOL deprecated;
+
+// The parser stores options it doesn't recognize here. See above.
+// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
+
+@end
+
+#pragma mark - GPBUninterpretedOption
+
+typedef GPB_ENUM(GPBUninterpretedOption_FieldNumber) {
+  GPBUninterpretedOption_FieldNumber_NameArray = 2,
+  GPBUninterpretedOption_FieldNumber_IdentifierValue = 3,
+  GPBUninterpretedOption_FieldNumber_PositiveIntValue = 4,
+  GPBUninterpretedOption_FieldNumber_NegativeIntValue = 5,
+  GPBUninterpretedOption_FieldNumber_DoubleValue = 6,
+  GPBUninterpretedOption_FieldNumber_StringValue = 7,
+  GPBUninterpretedOption_FieldNumber_AggregateValue = 8,
+};
+
+// 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.
+@interface GPBUninterpretedOption : GPBMessage
+
+// |nameArray| contains |GPBUninterpretedOption_NamePart|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nameArray;
+@property(nonatomic, readonly) NSUInteger nameArray_Count;
+
+// The value of the uninterpreted option, in whatever type the tokenizer
+// identified it as during parsing. Exactly one of these should be set.
+@property(nonatomic, readwrite) BOOL hasIdentifierValue;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *identifierValue;
+
+@property(nonatomic, readwrite) BOOL hasPositiveIntValue;
+@property(nonatomic, readwrite) uint64_t positiveIntValue;
+
+@property(nonatomic, readwrite) BOOL hasNegativeIntValue;
+@property(nonatomic, readwrite) int64_t negativeIntValue;
+
+@property(nonatomic, readwrite) BOOL hasDoubleValue;
+@property(nonatomic, readwrite) double doubleValue;
+
+@property(nonatomic, readwrite) BOOL hasStringValue;
+@property(nonatomic, readwrite, copy, null_resettable) NSData *stringValue;
+
+@property(nonatomic, readwrite) BOOL hasAggregateValue;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *aggregateValue;
+
+@end
+
+#pragma mark - GPBUninterpretedOption_NamePart
+
+typedef GPB_ENUM(GPBUninterpretedOption_NamePart_FieldNumber) {
+  GPBUninterpretedOption_NamePart_FieldNumber_NamePart = 1,
+  GPBUninterpretedOption_NamePart_FieldNumber_IsExtension = 2,
+};
+
+// 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".
+@interface GPBUninterpretedOption_NamePart : GPBMessage
+
+@property(nonatomic, readwrite) BOOL hasNamePart;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *namePart;
+
+@property(nonatomic, readwrite) BOOL hasIsExtension;
+@property(nonatomic, readwrite) BOOL isExtension;
+
+@end
+
+#pragma mark - GPBSourceCodeInfo
+
+typedef GPB_ENUM(GPBSourceCodeInfo_FieldNumber) {
+  GPBSourceCodeInfo_FieldNumber_LocationArray = 1,
+};
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+@interface GPBSourceCodeInfo : GPBMessage
+
+// 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.
+// |locationArray| contains |GPBSourceCodeInfo_Location|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *locationArray;
+@property(nonatomic, readonly) NSUInteger locationArray_Count;
+
+@end
+
+#pragma mark - GPBSourceCodeInfo_Location
+
+typedef GPB_ENUM(GPBSourceCodeInfo_Location_FieldNumber) {
+  GPBSourceCodeInfo_Location_FieldNumber_PathArray = 1,
+  GPBSourceCodeInfo_Location_FieldNumber_SpanArray = 2,
+  GPBSourceCodeInfo_Location_FieldNumber_LeadingComments = 3,
+  GPBSourceCodeInfo_Location_FieldNumber_TrailingComments = 4,
+  GPBSourceCodeInfo_Location_FieldNumber_LeadingDetachedCommentsArray = 6,
+};
+
+@interface GPBSourceCodeInfo_Location : GPBMessage
+
+// 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).
+@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *pathArray;
+@property(nonatomic, readonly) NSUInteger pathArray_Count;
+
+// 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.
+@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *spanArray;
+@property(nonatomic, readonly) NSUInteger spanArray_Count;
+
+// 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.
+@property(nonatomic, readwrite) BOOL hasLeadingComments;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *leadingComments;
+
+@property(nonatomic, readwrite) BOOL hasTrailingComments;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *trailingComments;
+
+// |leadingDetachedCommentsArray| contains |NSString|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *leadingDetachedCommentsArray;
+@property(nonatomic, readonly) NSUInteger leadingDetachedCommentsArray_Count;
+
+@end
+
+#pragma mark - GPBGeneratedCodeInfo
+
+typedef GPB_ENUM(GPBGeneratedCodeInfo_FieldNumber) {
+  GPBGeneratedCodeInfo_FieldNumber_AnnotationArray = 1,
+};
+
+// 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.
+@interface GPBGeneratedCodeInfo : GPBMessage
+
+// An Annotation connects some span of text in generated code to an element
+// of its generating .proto file.
+// |annotationArray| contains |GPBGeneratedCodeInfo_Annotation|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *annotationArray;
+@property(nonatomic, readonly) NSUInteger annotationArray_Count;
+
+@end
+
+#pragma mark - GPBGeneratedCodeInfo_Annotation
+
+typedef GPB_ENUM(GPBGeneratedCodeInfo_Annotation_FieldNumber) {
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_PathArray = 1,
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_SourceFile = 2,
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_Begin = 3,
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_End = 4,
+};
+
+@interface GPBGeneratedCodeInfo_Annotation : GPBMessage
+
+// Identifies the element in the original source .proto file. This field
+// is formatted the same as SourceCodeInfo.Location.path.
+@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *pathArray;
+@property(nonatomic, readonly) NSUInteger pathArray_Count;
+
+// Identifies the filesystem path to the original source .proto.
+@property(nonatomic, readwrite) BOOL hasSourceFile;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *sourceFile;
+
+// Identifies the starting offset in bytes in the generated code
+// that relates to the identified object.
+@property(nonatomic, readwrite) BOOL hasBegin;
+@property(nonatomic, readwrite) int32_t begin;
+
+// 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).
+@property(nonatomic, readwrite) BOOL hasEnd;
+@property(nonatomic, readwrite) int32_t end;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.m b/objectivec/google/protobuf/Descriptor.pbobjc.m
new file mode 100644
index 0000000..4030989
--- /dev/null
+++ b/objectivec/google/protobuf/Descriptor.pbobjc.m
@@ -0,0 +1,2594 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Descriptor.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBDescriptorRoot
+
+@implementation GPBDescriptorRoot
+
+@end
+
+#pragma mark - GPBDescriptorRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBDescriptorRoot_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:GPBFileSyntaxProto2];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBFileDescriptorSet
+
+@implementation GPBFileDescriptorSet
+
+@dynamic fileArray, fileArray_Count;
+
+typedef struct GPBFileDescriptorSet__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *fileArray;
+} GPBFileDescriptorSet__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 = "fileArray",
+        .number = GPBFileDescriptorSet_FieldNumber_FileArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorSet__storage_, fileArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBFileDescriptorProto),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFileDescriptorSet class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBFileDescriptorSet__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBFileDescriptorProto
+
+@implementation GPBFileDescriptorProto
+
+@dynamic hasName, name;
+@dynamic hasPackage, package;
+@dynamic dependencyArray, dependencyArray_Count;
+@dynamic publicDependencyArray, publicDependencyArray_Count;
+@dynamic weakDependencyArray, weakDependencyArray_Count;
+@dynamic messageTypeArray, messageTypeArray_Count;
+@dynamic enumTypeArray, enumTypeArray_Count;
+@dynamic serviceArray, serviceArray_Count;
+@dynamic extensionArray, extensionArray_Count;
+@dynamic hasOptions, options;
+@dynamic hasSourceCodeInfo, sourceCodeInfo;
+@dynamic hasSyntax, syntax;
+
+typedef struct GPBFileDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSString *package;
+  NSMutableArray *dependencyArray;
+  NSMutableArray *messageTypeArray;
+  NSMutableArray *enumTypeArray;
+  NSMutableArray *serviceArray;
+  NSMutableArray *extensionArray;
+  GPBFileOptions *options;
+  GPBSourceCodeInfo *sourceCodeInfo;
+  GPBInt32Array *publicDependencyArray;
+  GPBInt32Array *weakDependencyArray;
+  NSString *syntax;
+} GPBFileDescriptorProto__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",
+        .number = GPBFileDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "package",
+        .number = GPBFileDescriptorProto_FieldNumber_Package,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, package),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "dependencyArray",
+        .number = GPBFileDescriptorProto_FieldNumber_DependencyArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, dependencyArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "messageTypeArray",
+        .number = GPBFileDescriptorProto_FieldNumber_MessageTypeArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, messageTypeArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "enumTypeArray",
+        .number = GPBFileDescriptorProto_FieldNumber_EnumTypeArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, enumTypeArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "serviceArray",
+        .number = GPBFileDescriptorProto_FieldNumber_ServiceArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, serviceArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBServiceDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "extensionArray",
+        .number = GPBFileDescriptorProto_FieldNumber_ExtensionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, extensionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBFileDescriptorProto_FieldNumber_Options,
+        .hasIndex = 9,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBFileOptions),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceCodeInfo",
+        .number = GPBFileDescriptorProto_FieldNumber_SourceCodeInfo,
+        .hasIndex = 10,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, sourceCodeInfo),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceCodeInfo),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "publicDependencyArray",
+        .number = GPBFileDescriptorProto_FieldNumber_PublicDependencyArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, publicDependencyArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "weakDependencyArray",
+        .number = GPBFileDescriptorProto_FieldNumber_WeakDependencyArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, weakDependencyArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "syntax",
+        .number = GPBFileDescriptorProto_FieldNumber_Syntax,
+        .hasIndex = 11,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileDescriptorProto__storage_, syntax),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFileDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBFileDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBDescriptorProto
+
+@implementation GPBDescriptorProto
+
+@dynamic hasName, name;
+@dynamic fieldArray, fieldArray_Count;
+@dynamic extensionArray, extensionArray_Count;
+@dynamic nestedTypeArray, nestedTypeArray_Count;
+@dynamic enumTypeArray, enumTypeArray_Count;
+@dynamic extensionRangeArray, extensionRangeArray_Count;
+@dynamic oneofDeclArray, oneofDeclArray_Count;
+@dynamic hasOptions, options;
+@dynamic reservedRangeArray, reservedRangeArray_Count;
+@dynamic reservedNameArray, reservedNameArray_Count;
+
+typedef struct GPBDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSMutableArray *fieldArray;
+  NSMutableArray *nestedTypeArray;
+  NSMutableArray *enumTypeArray;
+  NSMutableArray *extensionRangeArray;
+  NSMutableArray *extensionArray;
+  GPBMessageOptions *options;
+  NSMutableArray *oneofDeclArray;
+  NSMutableArray *reservedRangeArray;
+  NSMutableArray *reservedNameArray;
+} GPBDescriptorProto__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",
+        .number = GPBDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "fieldArray",
+        .number = GPBDescriptorProto_FieldNumber_FieldArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, fieldArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "nestedTypeArray",
+        .number = GPBDescriptorProto_FieldNumber_NestedTypeArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, nestedTypeArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "enumTypeArray",
+        .number = GPBDescriptorProto_FieldNumber_EnumTypeArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, enumTypeArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "extensionRangeArray",
+        .number = GPBDescriptorProto_FieldNumber_ExtensionRangeArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, extensionRangeArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto_ExtensionRange),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "extensionArray",
+        .number = GPBDescriptorProto_FieldNumber_ExtensionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, extensionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBDescriptorProto_FieldNumber_Options,
+        .hasIndex = 7,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMessageOptions),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "oneofDeclArray",
+        .number = GPBDescriptorProto_FieldNumber_OneofDeclArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, oneofDeclArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOneofDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "reservedRangeArray",
+        .number = GPBDescriptorProto_FieldNumber_ReservedRangeArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBDescriptorProto__storage_, reservedRangeArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto_ReservedRange),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "reservedNameArray",
+        .number = GPBDescriptorProto_FieldNumber_ReservedNameArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBDescriptorProto__storage_, reservedNameArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBDescriptorProto_ExtensionRange
+
+@implementation GPBDescriptorProto_ExtensionRange
+
+@dynamic hasStart, start;
+@dynamic hasEnd, end;
+
+typedef struct GPBDescriptorProto_ExtensionRange__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t start;
+  int32_t end;
+} GPBDescriptorProto_ExtensionRange__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 = "start",
+        .number = GPBDescriptorProto_ExtensionRange_FieldNumber_Start,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBDescriptorProto_ExtensionRange__storage_, start),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "end",
+        .number = GPBDescriptorProto_ExtensionRange_FieldNumber_End,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBDescriptorProto_ExtensionRange__storage_, end),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto_ExtensionRange class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBDescriptorProto_ExtensionRange__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBDescriptorProto_ReservedRange
+
+@implementation GPBDescriptorProto_ReservedRange
+
+@dynamic hasStart, start;
+@dynamic hasEnd, end;
+
+typedef struct GPBDescriptorProto_ReservedRange__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t start;
+  int32_t end;
+} GPBDescriptorProto_ReservedRange__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 = "start",
+        .number = GPBDescriptorProto_ReservedRange_FieldNumber_Start,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBDescriptorProto_ReservedRange__storage_, start),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "end",
+        .number = GPBDescriptorProto_ReservedRange_FieldNumber_End,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBDescriptorProto_ReservedRange__storage_, end),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto_ReservedRange class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBDescriptorProto_ReservedRange__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBFieldDescriptorProto
+
+@implementation GPBFieldDescriptorProto
+
+@dynamic hasName, name;
+@dynamic hasNumber, number;
+@dynamic hasLabel, label;
+@dynamic hasType, type;
+@dynamic hasTypeName, typeName;
+@dynamic hasExtendee, extendee;
+@dynamic hasDefaultValue, defaultValue;
+@dynamic hasOneofIndex, oneofIndex;
+@dynamic hasJsonName, jsonName;
+@dynamic hasOptions, options;
+
+typedef struct GPBFieldDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t number;
+  GPBFieldDescriptorProto_Label label;
+  GPBFieldDescriptorProto_Type type;
+  int32_t oneofIndex;
+  NSString *name;
+  NSString *extendee;
+  NSString *typeName;
+  NSString *defaultValue;
+  GPBFieldOptions *options;
+  NSString *jsonName;
+} GPBFieldDescriptorProto__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",
+        .number = GPBFieldDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "extendee",
+        .number = GPBFieldDescriptorProto_FieldNumber_Extendee,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, extendee),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "number",
+        .number = GPBFieldDescriptorProto_FieldNumber_Number,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, number),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "label",
+        .number = GPBFieldDescriptorProto_FieldNumber_Label,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, label),
+        .defaultValue.valueEnum = GPBFieldDescriptorProto_Label_LabelOptional,
+        .dataTypeSpecific.enumDescFunc = GPBFieldDescriptorProto_Label_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "type",
+        .number = GPBFieldDescriptorProto_FieldNumber_Type,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, type),
+        .defaultValue.valueEnum = GPBFieldDescriptorProto_Type_TypeDouble,
+        .dataTypeSpecific.enumDescFunc = GPBFieldDescriptorProto_Type_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "typeName",
+        .number = GPBFieldDescriptorProto_FieldNumber_TypeName,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, typeName),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "defaultValue",
+        .number = GPBFieldDescriptorProto_FieldNumber_DefaultValue,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, defaultValue),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBFieldDescriptorProto_FieldNumber_Options,
+        .hasIndex = 9,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldOptions),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "oneofIndex",
+        .number = GPBFieldDescriptorProto_FieldNumber_OneofIndex,
+        .hasIndex = 7,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, oneofIndex),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "jsonName",
+        .number = GPBFieldDescriptorProto_FieldNumber_JsonName,
+        .hasIndex = 8,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, jsonName),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBMessageEnumDescription enums[] = {
+      { .enumDescriptorFunc = GPBFieldDescriptorProto_Type_EnumDescriptor },
+      { .enumDescriptorFunc = GPBFieldDescriptorProto_Label_EnumDescriptor },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFieldDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:enums
+                                     enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription)
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBFieldDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - Enum GPBFieldDescriptorProto_Type
+
+GPBEnumDescriptor *GPBFieldDescriptorProto_Type_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "TypeDouble", .number = GPBFieldDescriptorProto_Type_TypeDouble },
+      { .name = "TypeFloat", .number = GPBFieldDescriptorProto_Type_TypeFloat },
+      { .name = "TypeInt64", .number = GPBFieldDescriptorProto_Type_TypeInt64 },
+      { .name = "TypeUint64", .number = GPBFieldDescriptorProto_Type_TypeUint64 },
+      { .name = "TypeInt32", .number = GPBFieldDescriptorProto_Type_TypeInt32 },
+      { .name = "TypeFixed64", .number = GPBFieldDescriptorProto_Type_TypeFixed64 },
+      { .name = "TypeFixed32", .number = GPBFieldDescriptorProto_Type_TypeFixed32 },
+      { .name = "TypeBool", .number = GPBFieldDescriptorProto_Type_TypeBool },
+      { .name = "TypeString", .number = GPBFieldDescriptorProto_Type_TypeString },
+      { .name = "TypeGroup", .number = GPBFieldDescriptorProto_Type_TypeGroup },
+      { .name = "TypeMessage", .number = GPBFieldDescriptorProto_Type_TypeMessage },
+      { .name = "TypeBytes", .number = GPBFieldDescriptorProto_Type_TypeBytes },
+      { .name = "TypeUint32", .number = GPBFieldDescriptorProto_Type_TypeUint32 },
+      { .name = "TypeEnum", .number = GPBFieldDescriptorProto_Type_TypeEnum },
+      { .name = "TypeSfixed32", .number = GPBFieldDescriptorProto_Type_TypeSfixed32 },
+      { .name = "TypeSfixed64", .number = GPBFieldDescriptorProto_Type_TypeSfixed64 },
+      { .name = "TypeSint32", .number = GPBFieldDescriptorProto_Type_TypeSint32 },
+      { .name = "TypeSint64", .number = GPBFieldDescriptorProto_Type_TypeSint64 },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldDescriptorProto_Type)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBFieldDescriptorProto_Type_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBFieldDescriptorProto_Type_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBFieldDescriptorProto_Type_TypeDouble:
+    case GPBFieldDescriptorProto_Type_TypeFloat:
+    case GPBFieldDescriptorProto_Type_TypeInt64:
+    case GPBFieldDescriptorProto_Type_TypeUint64:
+    case GPBFieldDescriptorProto_Type_TypeInt32:
+    case GPBFieldDescriptorProto_Type_TypeFixed64:
+    case GPBFieldDescriptorProto_Type_TypeFixed32:
+    case GPBFieldDescriptorProto_Type_TypeBool:
+    case GPBFieldDescriptorProto_Type_TypeString:
+    case GPBFieldDescriptorProto_Type_TypeGroup:
+    case GPBFieldDescriptorProto_Type_TypeMessage:
+    case GPBFieldDescriptorProto_Type_TypeBytes:
+    case GPBFieldDescriptorProto_Type_TypeUint32:
+    case GPBFieldDescriptorProto_Type_TypeEnum:
+    case GPBFieldDescriptorProto_Type_TypeSfixed32:
+    case GPBFieldDescriptorProto_Type_TypeSfixed64:
+    case GPBFieldDescriptorProto_Type_TypeSint32:
+    case GPBFieldDescriptorProto_Type_TypeSint64:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - Enum GPBFieldDescriptorProto_Label
+
+GPBEnumDescriptor *GPBFieldDescriptorProto_Label_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "LabelOptional", .number = GPBFieldDescriptorProto_Label_LabelOptional },
+      { .name = "LabelRequired", .number = GPBFieldDescriptorProto_Label_LabelRequired },
+      { .name = "LabelRepeated", .number = GPBFieldDescriptorProto_Label_LabelRepeated },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldDescriptorProto_Label)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBFieldDescriptorProto_Label_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBFieldDescriptorProto_Label_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBFieldDescriptorProto_Label_LabelOptional:
+    case GPBFieldDescriptorProto_Label_LabelRequired:
+    case GPBFieldDescriptorProto_Label_LabelRepeated:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBOneofDescriptorProto
+
+@implementation GPBOneofDescriptorProto
+
+@dynamic hasName, name;
+
+typedef struct GPBOneofDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+} GPBOneofDescriptorProto__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",
+        .number = GPBOneofDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBOneofDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBOneofDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBOneofDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBEnumDescriptorProto
+
+@implementation GPBEnumDescriptorProto
+
+@dynamic hasName, name;
+@dynamic valueArray, valueArray_Count;
+@dynamic hasOptions, options;
+
+typedef struct GPBEnumDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSMutableArray *valueArray;
+  GPBEnumOptions *options;
+} GPBEnumDescriptorProto__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",
+        .number = GPBEnumDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBEnumDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "valueArray",
+        .number = GPBEnumDescriptorProto_FieldNumber_ValueArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnumDescriptorProto__storage_, valueArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValueDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBEnumDescriptorProto_FieldNumber_Options,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnumDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumOptions),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnumDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBEnumDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBEnumValueDescriptorProto
+
+@implementation GPBEnumValueDescriptorProto
+
+@dynamic hasName, name;
+@dynamic hasNumber, number;
+@dynamic hasOptions, options;
+
+typedef struct GPBEnumValueDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t number;
+  NSString *name;
+  GPBEnumValueOptions *options;
+} GPBEnumValueDescriptorProto__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",
+        .number = GPBEnumValueDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBEnumValueDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "number",
+        .number = GPBEnumValueDescriptorProto_FieldNumber_Number,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBEnumValueDescriptorProto__storage_, number),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBEnumValueDescriptorProto_FieldNumber_Options,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnumValueDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValueOptions),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnumValueDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBEnumValueDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBServiceDescriptorProto
+
+@implementation GPBServiceDescriptorProto
+
+@dynamic hasName, name;
+@dynamic methodArray, methodArray_Count;
+@dynamic hasOptions, options;
+
+typedef struct GPBServiceDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSMutableArray *methodArray;
+  GPBServiceOptions *options;
+} GPBServiceDescriptorProto__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",
+        .number = GPBServiceDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBServiceDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "methodArray",
+        .number = GPBServiceDescriptorProto_FieldNumber_MethodArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBServiceDescriptorProto__storage_, methodArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMethodDescriptorProto),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBServiceDescriptorProto_FieldNumber_Options,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBServiceDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBServiceOptions),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBServiceDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBServiceDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBMethodDescriptorProto
+
+@implementation GPBMethodDescriptorProto
+
+@dynamic hasName, name;
+@dynamic hasInputType, inputType;
+@dynamic hasOutputType, outputType;
+@dynamic hasOptions, options;
+@dynamic hasClientStreaming, clientStreaming;
+@dynamic hasServerStreaming, serverStreaming;
+
+typedef struct GPBMethodDescriptorProto__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL clientStreaming;
+  BOOL serverStreaming;
+  NSString *name;
+  NSString *inputType;
+  NSString *outputType;
+  GPBMethodOptions *options;
+} GPBMethodDescriptorProto__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",
+        .number = GPBMethodDescriptorProto_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMethodDescriptorProto__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "inputType",
+        .number = GPBMethodDescriptorProto_FieldNumber_InputType,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMethodDescriptorProto__storage_, inputType),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "outputType",
+        .number = GPBMethodDescriptorProto_FieldNumber_OutputType,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBMethodDescriptorProto__storage_, outputType),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "options",
+        .number = GPBMethodDescriptorProto_FieldNumber_Options,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBMethodDescriptorProto__storage_, options),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMethodOptions),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "clientStreaming",
+        .number = GPBMethodDescriptorProto_FieldNumber_ClientStreaming,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMethodDescriptorProto__storage_, clientStreaming),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "serverStreaming",
+        .number = GPBMethodDescriptorProto_FieldNumber_ServerStreaming,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMethodDescriptorProto__storage_, serverStreaming),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMethodDescriptorProto class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBMethodDescriptorProto__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBFileOptions
+
+@implementation GPBFileOptions
+
+@dynamic hasJavaPackage, javaPackage;
+@dynamic hasJavaOuterClassname, javaOuterClassname;
+@dynamic hasJavaMultipleFiles, javaMultipleFiles;
+@dynamic hasJavaGenerateEqualsAndHash, javaGenerateEqualsAndHash;
+@dynamic hasJavaStringCheckUtf8, javaStringCheckUtf8;
+@dynamic hasOptimizeFor, optimizeFor;
+@dynamic hasGoPackage, goPackage;
+@dynamic hasCcGenericServices, ccGenericServices;
+@dynamic hasJavaGenericServices, javaGenericServices;
+@dynamic hasPyGenericServices, pyGenericServices;
+@dynamic hasDeprecated, deprecated;
+@dynamic hasCcEnableArenas, ccEnableArenas;
+@dynamic hasObjcClassPrefix, objcClassPrefix;
+@dynamic hasCsharpNamespace, csharpNamespace;
+@dynamic hasJavananoUseDeprecatedPackage, javananoUseDeprecatedPackage;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBFileOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL javaMultipleFiles;
+  BOOL ccGenericServices;
+  BOOL javaGenericServices;
+  BOOL pyGenericServices;
+  BOOL javaGenerateEqualsAndHash;
+  BOOL deprecated;
+  BOOL javaStringCheckUtf8;
+  BOOL ccEnableArenas;
+  BOOL javananoUseDeprecatedPackage;
+  GPBFileOptions_OptimizeMode optimizeFor;
+  NSString *javaPackage;
+  NSString *javaOuterClassname;
+  NSString *goPackage;
+  NSString *objcClassPrefix;
+  NSString *csharpNamespace;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBFileOptions__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 = "javaPackage",
+        .number = GPBFileOptions_FieldNumber_JavaPackage,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileOptions__storage_, javaPackage),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "javaOuterClassname",
+        .number = GPBFileOptions_FieldNumber_JavaOuterClassname,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileOptions__storage_, javaOuterClassname),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optimizeFor",
+        .number = GPBFileOptions_FieldNumber_OptimizeFor,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBFileOptions__storage_, optimizeFor),
+        .defaultValue.valueEnum = GPBFileOptions_OptimizeMode_Speed,
+        .dataTypeSpecific.enumDescFunc = GPBFileOptions_OptimizeMode_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "javaMultipleFiles",
+        .number = GPBFileOptions_FieldNumber_JavaMultipleFiles,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, javaMultipleFiles),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "goPackage",
+        .number = GPBFileOptions_FieldNumber_GoPackage,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileOptions__storage_, goPackage),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "ccGenericServices",
+        .number = GPBFileOptions_FieldNumber_CcGenericServices,
+        .hasIndex = 7,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, ccGenericServices),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "javaGenericServices",
+        .number = GPBFileOptions_FieldNumber_JavaGenericServices,
+        .hasIndex = 8,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, javaGenericServices),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "pyGenericServices",
+        .number = GPBFileOptions_FieldNumber_PyGenericServices,
+        .hasIndex = 9,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, pyGenericServices),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "javaGenerateEqualsAndHash",
+        .number = GPBFileOptions_FieldNumber_JavaGenerateEqualsAndHash,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, javaGenerateEqualsAndHash),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "deprecated",
+        .number = GPBFileOptions_FieldNumber_Deprecated,
+        .hasIndex = 10,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "javaStringCheckUtf8",
+        .number = GPBFileOptions_FieldNumber_JavaStringCheckUtf8,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, javaStringCheckUtf8),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "ccEnableArenas",
+        .number = GPBFileOptions_FieldNumber_CcEnableArenas,
+        .hasIndex = 11,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, ccEnableArenas),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "objcClassPrefix",
+        .number = GPBFileOptions_FieldNumber_ObjcClassPrefix,
+        .hasIndex = 12,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileOptions__storage_, objcClassPrefix),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "csharpNamespace",
+        .number = GPBFileOptions_FieldNumber_CsharpNamespace,
+        .hasIndex = 13,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFileOptions__storage_, csharpNamespace),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "javananoUseDeprecatedPackage",
+        .number = GPBFileOptions_FieldNumber_JavananoUseDeprecatedPackage,
+        .hasIndex = 14,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFileOptions__storage_, javananoUseDeprecatedPackage),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+      #if GPBOBJC_INCLUDE_FIELD_OPTIONS
+        .fieldOptions = "\000\000\000\002\030\001",
+      #else
+        .fieldOptions = NULL,
+      #endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBFileOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFileOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBMessageEnumDescription enums[] = {
+      { .enumDescriptorFunc = GPBFileOptions_OptimizeMode_EnumDescriptor },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFileOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:enums
+                                     enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription)
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBFileOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - Enum GPBFileOptions_OptimizeMode
+
+GPBEnumDescriptor *GPBFileOptions_OptimizeMode_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "Speed", .number = GPBFileOptions_OptimizeMode_Speed },
+      { .name = "CodeSize", .number = GPBFileOptions_OptimizeMode_CodeSize },
+      { .name = "LiteRuntime", .number = GPBFileOptions_OptimizeMode_LiteRuntime },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFileOptions_OptimizeMode)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBFileOptions_OptimizeMode_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBFileOptions_OptimizeMode_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBFileOptions_OptimizeMode_Speed:
+    case GPBFileOptions_OptimizeMode_CodeSize:
+    case GPBFileOptions_OptimizeMode_LiteRuntime:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBMessageOptions
+
+@implementation GPBMessageOptions
+
+@dynamic hasMessageSetWireFormat, messageSetWireFormat;
+@dynamic hasNoStandardDescriptorAccessor, noStandardDescriptorAccessor;
+@dynamic hasDeprecated, deprecated;
+@dynamic hasMapEntry, mapEntry;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBMessageOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL messageSetWireFormat;
+  BOOL noStandardDescriptorAccessor;
+  BOOL deprecated;
+  BOOL mapEntry;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBMessageOptions__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 = "messageSetWireFormat",
+        .number = GPBMessageOptions_FieldNumber_MessageSetWireFormat,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMessageOptions__storage_, messageSetWireFormat),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "noStandardDescriptorAccessor",
+        .number = GPBMessageOptions_FieldNumber_NoStandardDescriptorAccessor,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMessageOptions__storage_, noStandardDescriptorAccessor),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "deprecated",
+        .number = GPBMessageOptions_FieldNumber_Deprecated,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMessageOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "mapEntry",
+        .number = GPBMessageOptions_FieldNumber_MapEntry,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMessageOptions__storage_, mapEntry),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBMessageOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBMessageOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMessageOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBMessageOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBFieldOptions
+
+@implementation GPBFieldOptions
+
+@dynamic hasCtype, ctype;
+@dynamic hasPacked, packed;
+@dynamic hasJstype, jstype;
+@dynamic hasLazy, lazy;
+@dynamic hasDeprecated, deprecated;
+@dynamic hasWeak, weak;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBFieldOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL packed;
+  BOOL deprecated;
+  BOOL lazy;
+  BOOL weak;
+  GPBFieldOptions_CType ctype;
+  GPBFieldOptions_JSType jstype;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBFieldOptions__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 = "ctype",
+        .number = GPBFieldOptions_FieldNumber_Ctype,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBFieldOptions__storage_, ctype),
+        .defaultValue.valueEnum = GPBFieldOptions_CType_String,
+        .dataTypeSpecific.enumDescFunc = GPBFieldOptions_CType_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "packed",
+        .number = GPBFieldOptions_FieldNumber_Packed,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFieldOptions__storage_, packed),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "deprecated",
+        .number = GPBFieldOptions_FieldNumber_Deprecated,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFieldOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "lazy",
+        .number = GPBFieldOptions_FieldNumber_Lazy,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFieldOptions__storage_, lazy),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "jstype",
+        .number = GPBFieldOptions_FieldNumber_Jstype,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBFieldOptions__storage_, jstype),
+        .defaultValue.valueEnum = GPBFieldOptions_JSType_JsNormal,
+        .dataTypeSpecific.enumDescFunc = GPBFieldOptions_JSType_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "weak",
+        .number = GPBFieldOptions_FieldNumber_Weak,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBFieldOptions__storage_, weak),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBFieldOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBFieldOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBMessageEnumDescription enums[] = {
+      { .enumDescriptorFunc = GPBFieldOptions_CType_EnumDescriptor },
+      { .enumDescriptorFunc = GPBFieldOptions_JSType_EnumDescriptor },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFieldOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:enums
+                                     enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription)
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBFieldOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - Enum GPBFieldOptions_CType
+
+GPBEnumDescriptor *GPBFieldOptions_CType_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "String", .number = GPBFieldOptions_CType_String },
+      { .name = "Cord", .number = GPBFieldOptions_CType_Cord },
+      { .name = "StringPiece", .number = GPBFieldOptions_CType_StringPiece },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldOptions_CType)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBFieldOptions_CType_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBFieldOptions_CType_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBFieldOptions_CType_String:
+    case GPBFieldOptions_CType_Cord:
+    case GPBFieldOptions_CType_StringPiece:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - Enum GPBFieldOptions_JSType
+
+GPBEnumDescriptor *GPBFieldOptions_JSType_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "JsNormal", .number = GPBFieldOptions_JSType_JsNormal },
+      { .name = "JsString", .number = GPBFieldOptions_JSType_JsString },
+      { .name = "JsNumber", .number = GPBFieldOptions_JSType_JsNumber },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldOptions_JSType)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBFieldOptions_JSType_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBFieldOptions_JSType_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBFieldOptions_JSType_JsNormal:
+    case GPBFieldOptions_JSType_JsString:
+    case GPBFieldOptions_JSType_JsNumber:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBEnumOptions
+
+@implementation GPBEnumOptions
+
+@dynamic hasAllowAlias, allowAlias;
+@dynamic hasDeprecated, deprecated;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBEnumOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL allowAlias;
+  BOOL deprecated;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBEnumOptions__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 = "allowAlias",
+        .number = GPBEnumOptions_FieldNumber_AllowAlias,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBEnumOptions__storage_, allowAlias),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "deprecated",
+        .number = GPBEnumOptions_FieldNumber_Deprecated,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBEnumOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBEnumOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnumOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnumOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBEnumOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBEnumValueOptions
+
+@implementation GPBEnumValueOptions
+
+@dynamic hasDeprecated, deprecated;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBEnumValueOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL deprecated;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBEnumValueOptions__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 = "deprecated",
+        .number = GPBEnumValueOptions_FieldNumber_Deprecated,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBEnumValueOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBEnumValueOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnumValueOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnumValueOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBEnumValueOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBServiceOptions
+
+@implementation GPBServiceOptions
+
+@dynamic hasDeprecated, deprecated;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBServiceOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL deprecated;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBServiceOptions__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 = "deprecated",
+        .number = GPBServiceOptions_FieldNumber_Deprecated,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBServiceOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBServiceOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBServiceOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBServiceOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBServiceOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBMethodOptions
+
+@implementation GPBMethodOptions
+
+@dynamic hasDeprecated, deprecated;
+@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count;
+
+typedef struct GPBMethodOptions__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL deprecated;
+  NSMutableArray *uninterpretedOptionArray;
+} GPBMethodOptions__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 = "deprecated",
+        .number = GPBMethodOptions_FieldNumber_Deprecated,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasDefaultValue,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBMethodOptions__storage_, deprecated),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "uninterpretedOptionArray",
+        .number = GPBMethodOptions_FieldNumber_UninterpretedOptionArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBMethodOptions__storage_, uninterpretedOptionArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBExtensionRange ranges[] = {
+      { .start = 1000, .end = 536870912 },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMethodOptions class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:ranges
+                                    rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange)
+                                   storageSize:sizeof(GPBMethodOptions__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBUninterpretedOption
+
+@implementation GPBUninterpretedOption
+
+@dynamic nameArray, nameArray_Count;
+@dynamic hasIdentifierValue, identifierValue;
+@dynamic hasPositiveIntValue, positiveIntValue;
+@dynamic hasNegativeIntValue, negativeIntValue;
+@dynamic hasDoubleValue, doubleValue;
+@dynamic hasStringValue, stringValue;
+@dynamic hasAggregateValue, aggregateValue;
+
+typedef struct GPBUninterpretedOption__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *nameArray;
+  NSString *identifierValue;
+  NSData *stringValue;
+  NSString *aggregateValue;
+  uint64_t positiveIntValue;
+  int64_t negativeIntValue;
+  double doubleValue;
+} GPBUninterpretedOption__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 = "nameArray",
+        .number = GPBUninterpretedOption_FieldNumber_NameArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBUninterpretedOption__storage_, nameArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption_NamePart),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "identifierValue",
+        .number = GPBUninterpretedOption_FieldNumber_IdentifierValue,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBUninterpretedOption__storage_, identifierValue),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "positiveIntValue",
+        .number = GPBUninterpretedOption_FieldNumber_PositiveIntValue,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeUInt64,
+        .offset = offsetof(GPBUninterpretedOption__storage_, positiveIntValue),
+        .defaultValue.valueUInt64 = 0ULL,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "negativeIntValue",
+        .number = GPBUninterpretedOption_FieldNumber_NegativeIntValue,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+        .offset = offsetof(GPBUninterpretedOption__storage_, negativeIntValue),
+        .defaultValue.valueInt64 = 0LL,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "doubleValue",
+        .number = GPBUninterpretedOption_FieldNumber_DoubleValue,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeDouble,
+        .offset = offsetof(GPBUninterpretedOption__storage_, doubleValue),
+        .defaultValue.valueDouble = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "stringValue",
+        .number = GPBUninterpretedOption_FieldNumber_StringValue,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBytes,
+        .offset = offsetof(GPBUninterpretedOption__storage_, stringValue),
+        .defaultValue.valueData = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "aggregateValue",
+        .number = GPBUninterpretedOption_FieldNumber_AggregateValue,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBUninterpretedOption__storage_, aggregateValue),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBUninterpretedOption class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBUninterpretedOption__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBUninterpretedOption_NamePart
+
+@implementation GPBUninterpretedOption_NamePart
+
+@dynamic hasNamePart, namePart;
+@dynamic hasIsExtension, isExtension;
+
+typedef struct GPBUninterpretedOption_NamePart__storage_ {
+  uint32_t _has_storage_[1];
+  BOOL isExtension;
+  NSString *namePart;
+} GPBUninterpretedOption_NamePart__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 = "namePart",
+        .number = GPBUninterpretedOption_NamePart_FieldNumber_NamePart,
+        .hasIndex = 0,
+        .flags = GPBFieldRequired,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBUninterpretedOption_NamePart__storage_, namePart),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "isExtension",
+        .number = GPBUninterpretedOption_NamePart_FieldNumber_IsExtension,
+        .hasIndex = 1,
+        .flags = GPBFieldRequired,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBUninterpretedOption_NamePart__storage_, isExtension),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBUninterpretedOption_NamePart class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBUninterpretedOption_NamePart__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBSourceCodeInfo
+
+@implementation GPBSourceCodeInfo
+
+@dynamic locationArray, locationArray_Count;
+
+typedef struct GPBSourceCodeInfo__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *locationArray;
+} GPBSourceCodeInfo__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 = "locationArray",
+        .number = GPBSourceCodeInfo_FieldNumber_LocationArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBSourceCodeInfo__storage_, locationArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceCodeInfo_Location),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBSourceCodeInfo class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBSourceCodeInfo__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBSourceCodeInfo_Location
+
+@implementation GPBSourceCodeInfo_Location
+
+@dynamic pathArray, pathArray_Count;
+@dynamic spanArray, spanArray_Count;
+@dynamic hasLeadingComments, leadingComments;
+@dynamic hasTrailingComments, trailingComments;
+@dynamic leadingDetachedCommentsArray, leadingDetachedCommentsArray_Count;
+
+typedef struct GPBSourceCodeInfo_Location__storage_ {
+  uint32_t _has_storage_[1];
+  GPBInt32Array *pathArray;
+  GPBInt32Array *spanArray;
+  NSString *leadingComments;
+  NSString *trailingComments;
+  NSMutableArray *leadingDetachedCommentsArray;
+} GPBSourceCodeInfo_Location__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 = "pathArray",
+        .number = GPBSourceCodeInfo_Location_FieldNumber_PathArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated | GPBFieldPacked,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBSourceCodeInfo_Location__storage_, pathArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+      #if GPBOBJC_INCLUDE_FIELD_OPTIONS
+        .fieldOptions = "\000\000\000\002\020\001",
+      #else
+        .fieldOptions = NULL,
+      #endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS
+      },
+      {
+        .name = "spanArray",
+        .number = GPBSourceCodeInfo_Location_FieldNumber_SpanArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated | GPBFieldPacked,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBSourceCodeInfo_Location__storage_, spanArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+      #if GPBOBJC_INCLUDE_FIELD_OPTIONS
+        .fieldOptions = "\000\000\000\002\020\001",
+      #else
+        .fieldOptions = NULL,
+      #endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS
+      },
+      {
+        .name = "leadingComments",
+        .number = GPBSourceCodeInfo_Location_FieldNumber_LeadingComments,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBSourceCodeInfo_Location__storage_, leadingComments),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "trailingComments",
+        .number = GPBSourceCodeInfo_Location_FieldNumber_TrailingComments,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBSourceCodeInfo_Location__storage_, trailingComments),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "leadingDetachedCommentsArray",
+        .number = GPBSourceCodeInfo_Location_FieldNumber_LeadingDetachedCommentsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBSourceCodeInfo_Location__storage_, leadingDetachedCommentsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBSourceCodeInfo_Location class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBSourceCodeInfo_Location__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBGeneratedCodeInfo
+
+@implementation GPBGeneratedCodeInfo
+
+@dynamic annotationArray, annotationArray_Count;
+
+typedef struct GPBGeneratedCodeInfo__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *annotationArray;
+} GPBGeneratedCodeInfo__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 = "annotationArray",
+        .number = GPBGeneratedCodeInfo_FieldNumber_AnnotationArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBGeneratedCodeInfo__storage_, annotationArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBGeneratedCodeInfo_Annotation),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBGeneratedCodeInfo class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBGeneratedCodeInfo__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBGeneratedCodeInfo_Annotation
+
+@implementation GPBGeneratedCodeInfo_Annotation
+
+@dynamic pathArray, pathArray_Count;
+@dynamic hasSourceFile, sourceFile;
+@dynamic hasBegin, begin;
+@dynamic hasEnd, end;
+
+typedef struct GPBGeneratedCodeInfo_Annotation__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t begin;
+  int32_t end;
+  GPBInt32Array *pathArray;
+  NSString *sourceFile;
+} GPBGeneratedCodeInfo_Annotation__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 = "pathArray",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_PathArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated | GPBFieldPacked,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, pathArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+      #if GPBOBJC_INCLUDE_FIELD_OPTIONS
+        .fieldOptions = "\000\000\000\002\020\001",
+      #else
+        .fieldOptions = NULL,
+      #endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS
+      },
+      {
+        .name = "sourceFile",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_SourceFile,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, sourceFile),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "begin",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_Begin,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, begin),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "end",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_End,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, end),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBGeneratedCodeInfo_Annotation class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBGeneratedCodeInfo_Annotation__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..b592640
--- /dev/null
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -0,0 +1,94 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBDurationRoot
+
+@interface GPBDurationRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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
+
+// @@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..e4fd495
--- /dev/null
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -0,0 +1,93 @@
+// 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 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",
+        .number = GPBDuration_FieldNumber_Seconds,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+        .offset = offsetof(GPBDuration__storage_, seconds),
+        .defaultValue.valueInt64 = 0LL,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "nanos",
+        .number = GPBDuration_FieldNumber_Nanos,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBDuration__storage_, nanos),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDuration class]
+                                     rootClass:[GPBDurationRoot class]
+                                          file:GPBDurationRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBDuration__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..bace614
--- /dev/null
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -0,0 +1,46 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBEmptyRoot
+
+@interface GPBEmptyRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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
+
+// @@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..17f0c1a
--- /dev/null
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -0,0 +1,65 @@
+// 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 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_[0];
+} 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
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBEmpty__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..4e4ec38
--- /dev/null
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -0,0 +1,168 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBFieldMaskRoot
+
+@interface GPBFieldMaskRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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 applies 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"
+//     }
+@interface GPBFieldMask : GPBMessage
+
+// The set of field mask paths.
+// |pathsArray| contains |NSString|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *pathsArray;
+@property(nonatomic, readonly) NSUInteger pathsArray_Count;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+// @@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..f9684f5
--- /dev/null
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -0,0 +1,80 @@
+// 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 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",
+        .number = GPBFieldMask_FieldNumber_PathsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldMask__storage_, pathsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFieldMask class]
+                                     rootClass:[GPBFieldMaskRoot class]
+                                          file:GPBFieldMaskRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBFieldMask__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..8480db1
--- /dev/null
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -0,0 +1,47 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBSourceContextRoot
+
+@interface GPBSourceContextRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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
+
+// @@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..ac1827f
--- /dev/null
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -0,0 +1,80 @@
+// 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 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",
+        .number = GPBSourceContext_FieldNumber_FileName,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBSourceContext__storage_, fileName),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBSourceContext class]
+                                     rootClass:[GPBSourceContextRoot class]
+                                          file:GPBSourceContextRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBSourceContext__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..f40414f
--- /dev/null
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -0,0 +1,148 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBListValue;
+@class GPBStruct;
+
+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) {
+  GPBNullValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  // Null value.
+  GPBNullValue_NullValue = 0,
+};
+
+GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void);
+
+BOOL GPBNullValue_IsValidValue(int32_t value);
+
+#pragma mark - GPBStructRoot
+
+@interface GPBStructRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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
+
+// Map of dynamically typed values.
+// |fields| values are |GPBValue|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields;
+@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
+
+int32_t GPBValue_NullValue_RawValue(GPBValue *message);
+void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value);
+
+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.
+// |valuesArray| contains |GPBValue|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valuesArray;
+@property(nonatomic, readonly) NSUInteger valuesArray_Count;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+// @@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..14b8f27
--- /dev/null
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -0,0 +1,296 @@
+// 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 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 GPBMessageEnumValueDescription values[] = {
+      { .name = "NullValue", .number = GPBNullValue_NullValue },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBNullValue_IsValidValue];
+  }
+  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",
+        .number = GPBStruct_FieldNumber_Fields,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldMapKeyString,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBStruct__storage_, fields),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBValue),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBStruct class]
+                                     rootClass:[GPBStructRoot class]
+                                          file:GPBStructRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBStruct__storage_)
+                                    wireFormat:NO];
+    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];
+  BOOL boolValue;
+  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 GPBMessageOneofDescription oneofs[] = {
+      {
+        .name = "kind",
+        .index = -1,
+      },
+    };
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "nullValue",
+        .number = GPBValue_FieldNumber_NullValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBValue__storage_, nullValue),
+        .defaultValue.valueEnum = GPBNullValue_NullValue,
+        .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "numberValue",
+        .number = GPBValue_FieldNumber_NumberValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeDouble,
+        .offset = offsetof(GPBValue__storage_, numberValue),
+        .defaultValue.valueDouble = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "stringValue",
+        .number = GPBValue_FieldNumber_StringValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBValue__storage_, stringValue),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "boolValue",
+        .number = GPBValue_FieldNumber_BoolValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBValue__storage_, boolValue),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "structValue",
+        .number = GPBValue_FieldNumber_StructValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBValue__storage_, structValue),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "listValue",
+        .number = GPBValue_FieldNumber_ListValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBValue__storage_, listValue),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBValue class]
+                                     rootClass:[GPBStructRoot class]
+                                          file:GPBStructRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:oneofs
+                                    oneofCount:sizeof(oneofs) / sizeof(GPBMessageOneofDescription)
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBValue__storage_)
+                                    wireFormat:NO];
+    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, 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",
+        .number = GPBListValue_FieldNumber_ValuesArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBListValue__storage_, valuesArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBValue),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBListValue class]
+                                     rootClass:[GPBStructRoot class]
+                                          file:GPBStructRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBListValue__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..79b24ec
--- /dev/null
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -0,0 +1,106 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBTimestampRoot
+
+@interface GPBTimestampRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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
+
+// @@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..a206f15
--- /dev/null
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -0,0 +1,93 @@
+// 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 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",
+        .number = GPBTimestamp_FieldNumber_Seconds,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+        .offset = offsetof(GPBTimestamp__storage_, seconds),
+        .defaultValue.valueInt64 = 0LL,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "nanos",
+        .number = GPBTimestamp_FieldNumber_Nanos,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBTimestamp__storage_, nanos),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBTimestamp class]
+                                     rootClass:[GPBTimestampRoot class]
+                                          file:GPBTimestampRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBTimestamp__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..e4c7a25
--- /dev/null
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -0,0 +1,325 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBAny;
+@class GPBSourceContext;
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - Enum GPBSyntax
+
+// The syntax in which a protocol buffer element is defined.
+typedef GPB_ENUM(GPBSyntax) {
+  GPBSyntax_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  // Syntax `proto2`.
+  GPBSyntax_SyntaxProto2 = 0,
+
+  // Syntax `proto3`.
+  GPBSyntax_SyntaxProto3 = 1,
+};
+
+GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void);
+
+BOOL GPBSyntax_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBField_Kind
+
+// Basic field types.
+typedef GPB_ENUM(GPBField_Kind) {
+  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);
+
+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) {
+  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);
+
+BOOL GPBField_Cardinality_IsValidValue(int32_t value);
+
+#pragma mark - GPBTypeRoot
+
+@interface GPBTypeRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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.
+// |fieldsArray| contains |GPBField|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldsArray;
+@property(nonatomic, readonly) NSUInteger fieldsArray_Count;
+
+// The list of types appearing in `oneof` definitions in this type.
+// |oneofsArray| contains |NSString|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofsArray;
+@property(nonatomic, readonly) NSUInteger oneofsArray_Count;
+
+// The protocol buffer options.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+// The source context.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
+
+// The source syntax.
+@property(nonatomic, readwrite) GPBSyntax syntax;
+
+@end
+
+int32_t GPBType_Syntax_RawValue(GPBType *message);
+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.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@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
+
+int32_t GPBField_Kind_RawValue(GPBField *message);
+void SetGPBField_Kind_RawValue(GPBField *message, int32_t value);
+
+int32_t GPBField_Cardinality_RawValue(GPBField *message);
+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.
+// |enumvalueArray| contains |GPBEnumValue|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumvalueArray;
+@property(nonatomic, readonly) NSUInteger enumvalueArray_Count;
+
+// Protocol buffer options.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+// The source context.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
+
+// The source syntax.
+@property(nonatomic, readwrite) GPBSyntax syntax;
+
+@end
+
+int32_t GPBEnum_Syntax_RawValue(GPBEnum *message);
+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.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@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) BOOL hasValue;
+@property(nonatomic, readwrite, strong, null_resettable) GPBAny *value;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+// @@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..b4e0a5f
--- /dev/null
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -0,0 +1,749 @@
+// 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 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 GPBMessageEnumValueDescription values[] = {
+      { .name = "SyntaxProto2", .number = GPBSyntax_SyntaxProto2 },
+      { .name = "SyntaxProto3", .number = GPBSyntax_SyntaxProto3 },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBSyntax_IsValidValue];
+  }
+  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",
+        .number = GPBType_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBType__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "fieldsArray",
+        .number = GPBType_FieldNumber_FieldsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBType__storage_, fieldsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBField),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "oneofsArray",
+        .number = GPBType_FieldNumber_OneofsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBType__storage_, oneofsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBType_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBType__storage_, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceContext",
+        .number = GPBType_FieldNumber_SourceContext,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBType__storage_, sourceContext),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "syntax",
+        .number = GPBType_FieldNumber_Syntax,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBType__storage_, syntax),
+        .defaultValue.valueEnum = GPBSyntax_SyntaxProto2,
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBType class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBType__storage_)
+                                    wireFormat:NO];
+    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];
+  BOOL packed;
+  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",
+        .number = GPBField_FieldNumber_Kind,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBField__storage_, kind),
+        .defaultValue.valueEnum = GPBField_Kind_TypeUnknown,
+        .dataTypeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "cardinality",
+        .number = GPBField_FieldNumber_Cardinality,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBField__storage_, cardinality),
+        .defaultValue.valueEnum = GPBField_Cardinality_CardinalityUnknown,
+        .dataTypeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "number",
+        .number = GPBField_FieldNumber_Number,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBField__storage_, number),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "name",
+        .number = GPBField_FieldNumber_Name,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBField__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "typeURL",
+        .number = GPBField_FieldNumber_TypeURL,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBField__storage_, typeURL),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "oneofIndex",
+        .number = GPBField_FieldNumber_OneofIndex,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBField__storage_, oneofIndex),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "packed",
+        .number = GPBField_FieldNumber_Packed,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBField__storage_, packed),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBField_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBField__storage_, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "jsonName",
+        .number = GPBField_FieldNumber_JsonName,
+        .hasIndex = 8,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBField__storage_, jsonName),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "defaultValue",
+        .number = GPBField_FieldNumber_DefaultValue,
+        .hasIndex = 9,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBField__storage_, defaultValue),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBMessageEnumDescription enums[] = {
+      { .enumDescriptorFunc = GPBField_Kind_EnumDescriptor },
+      { .enumDescriptorFunc = GPBField_Cardinality_EnumDescriptor },
+    };
+#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    const char *extraTextFormatInfo = NULL;
+#else
+    static const char *extraTextFormatInfo = "\001\006\004\241!!\000";
+#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBField class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:enums
+                                     enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription)
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBField__storage_)
+                                    wireFormat:NO
+                           extraTextFormatInfo:extraTextFormatInfo];
+    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 GPBMessageEnumValueDescription values[] = {
+      { .name = "TypeUnknown", .number = GPBField_Kind_TypeUnknown },
+      { .name = "TypeDouble", .number = GPBField_Kind_TypeDouble },
+      { .name = "TypeFloat", .number = GPBField_Kind_TypeFloat },
+      { .name = "TypeInt64", .number = GPBField_Kind_TypeInt64 },
+      { .name = "TypeUint64", .number = GPBField_Kind_TypeUint64 },
+      { .name = "TypeInt32", .number = GPBField_Kind_TypeInt32 },
+      { .name = "TypeFixed64", .number = GPBField_Kind_TypeFixed64 },
+      { .name = "TypeFixed32", .number = GPBField_Kind_TypeFixed32 },
+      { .name = "TypeBool", .number = GPBField_Kind_TypeBool },
+      { .name = "TypeString", .number = GPBField_Kind_TypeString },
+      { .name = "TypeGroup", .number = GPBField_Kind_TypeGroup },
+      { .name = "TypeMessage", .number = GPBField_Kind_TypeMessage },
+      { .name = "TypeBytes", .number = GPBField_Kind_TypeBytes },
+      { .name = "TypeUint32", .number = GPBField_Kind_TypeUint32 },
+      { .name = "TypeEnum", .number = GPBField_Kind_TypeEnum },
+      { .name = "TypeSfixed32", .number = GPBField_Kind_TypeSfixed32 },
+      { .name = "TypeSfixed64", .number = GPBField_Kind_TypeSfixed64 },
+      { .name = "TypeSint32", .number = GPBField_Kind_TypeSint32 },
+      { .name = "TypeSint64", .number = GPBField_Kind_TypeSint64 },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBField_Kind_IsValidValue];
+  }
+  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 GPBMessageEnumValueDescription values[] = {
+      { .name = "CardinalityUnknown", .number = GPBField_Cardinality_CardinalityUnknown },
+      { .name = "CardinalityOptional", .number = GPBField_Cardinality_CardinalityOptional },
+      { .name = "CardinalityRequired", .number = GPBField_Cardinality_CardinalityRequired },
+      { .name = "CardinalityRepeated", .number = GPBField_Cardinality_CardinalityRepeated },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBField_Cardinality_IsValidValue];
+  }
+  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",
+        .number = GPBEnum_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBEnum__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "enumvalueArray",
+        .number = GPBEnum_FieldNumber_EnumvalueArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnum__storage_, enumvalueArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBEnum_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnum__storage_, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceContext",
+        .number = GPBEnum_FieldNumber_SourceContext,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnum__storage_, sourceContext),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "syntax",
+        .number = GPBEnum_FieldNumber_Syntax,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+        .offset = offsetof(GPBEnum__storage_, syntax),
+        .defaultValue.valueEnum = GPBSyntax_SyntaxProto2,
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnum class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBEnum__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBEnumValue_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBEnumValue__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "number",
+        .number = GPBEnumValue_FieldNumber_Number,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBEnumValue__storage_, number),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBEnumValue_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBEnumValue__storage_, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnumValue class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBEnumValue__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBOption_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBOption__storage_, name),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "value",
+        .number = GPBOption_FieldNumber_Value,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBOption__storage_, value),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBAny),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBOption class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBOption__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@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..580945c
--- /dev/null
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -0,0 +1,175 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#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)
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBWrappersRoot
+
+@interface GPBWrappersRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@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
+
+// @@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..0403b46
--- /dev/null
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -0,0 +1,488 @@
+// 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 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",
+        .number = GPBDoubleValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeDouble,
+        .offset = offsetof(GPBDoubleValue__storage_, value),
+        .defaultValue.valueDouble = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDoubleValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBDoubleValue__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBFloatValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeFloat,
+        .offset = offsetof(GPBFloatValue__storage_, value),
+        .defaultValue.valueFloat = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFloatValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBFloatValue__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBInt64Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+        .offset = offsetof(GPBInt64Value__storage_, value),
+        .defaultValue.valueInt64 = 0LL,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBInt64Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBInt64Value__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBUInt64Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeUInt64,
+        .offset = offsetof(GPBUInt64Value__storage_, value),
+        .defaultValue.valueUInt64 = 0ULL,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBUInt64Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBUInt64Value__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBInt32Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBInt32Value__storage_, value),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBInt32Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBInt32Value__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBUInt32Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeUInt32,
+        .offset = offsetof(GPBUInt32Value__storage_, value),
+        .defaultValue.valueUInt32 = 0U,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBUInt32Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBUInt32Value__storage_)
+                                    wireFormat:NO];
+    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];
+  BOOL value;
+} 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",
+        .number = GPBBoolValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+        .offset = offsetof(GPBBoolValue__storage_, value),
+        .defaultValue.valueBool = NO,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBBoolValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBBoolValue__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBStringValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBStringValue__storage_, value),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBStringValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBStringValue__storage_)
+                                    wireFormat:NO];
+    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",
+        .number = GPBBytesValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBytes,
+        .offset = offsetof(GPBBytesValue__storage_, value),
+        .defaultValue.valueData = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBBytesValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBBytesValue__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/post_process_dist.sh b/post_process_dist.sh
index 3c01ed8..82736bd 100755
--- a/post_process_dist.sh
+++ b/post_process_dist.sh
@@ -27,7 +27,7 @@
 
 set -ex
 
-LANGUAGES="cpp java javanano python ruby"
+LANGUAGES="cpp csharp java javanano js objectivec python ruby"
 BASENAME=`basename $1 .tar.gz`
 VERSION=${BASENAME:9}
 
@@ -40,11 +40,7 @@
 
 # Set the entire contents to be user-writable.
 chmod -R u+w $BASENAME
-
-# Convert the MSVC projects to MSVC 2005 format.
-cd $BASENAME/vsprojects
-./convert2008to2005.sh
-cd ..
+cd $BASENAME
 
 for LANG in $LANGUAGES; do
   # Build the dist again in .tar.gz
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..f674a6c
--- /dev/null
+++ b/protobuf.bzl
@@ -0,0 +1,295 @@
+# -*- 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):
+  return [s[:-len(".proto")] +  ".pb.h" for s in srcs] + \
+         [s[:-len(".proto")] + ".pb.cc" for s in srcs]
+
+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 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,
+        ),
+        "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="//google/protobuf:protoc",
+        internal_bootstrap_hack=False,
+        default_runtime="//google/protobuf: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.
+    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
+
+  outs = _CcOuts(srcs)
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      gen_cc=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if default_runtime and not default_runtime in cc_libs:
+    cc_libs += [default_runtime]
+
+  native.cc_library(
+      name=name,
+      srcs=outs,
+      deps=cc_libs + deps,
+      includes=includes,
+      **kargs)
+
+
+def internal_copied_filegroup(
+        name,
+        srcs,
+        include,
+        **kargs):
+  """Bazel rule to fix sources file to workaround with python path issues.
+
+  Args:
+    name: the name of the internal_copied_filegroup rule, which will be the
+        name of the generated filegroup.
+    srcs: the source files to be copied.
+    include: the expected import root of the source.
+    **kargs: extra arguments that will be passed into the filegroup.
+  """
+  outs = [_RelativeOutputPath(s, include) for s in srcs]
+
+  native.genrule(
+      name=name+"_genrule",
+      srcs=srcs,
+      outs=outs,
+      cmd=" && ".join(["cp $(location %s) $(location %s)" %
+                       (s, _RelativeOutputPath(s, include))
+                       for s in srcs]))
+
+  native.filegroup(
+      name=name,
+      srcs=outs,
+      **kargs)
+
+
+def py_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        py_libs=[],
+        py_extra_srcs=[],
+        include=None,
+        default_runtime="//google/protobuf:protobuf_python",
+        protoc="//google/protobuf: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 include != None:
+    # Copy the output files to the desired location to make the import work.
+    internal_copied_filegroup_name=name + "_internal_copied_filegroup"
+    internal_copied_filegroup(
+        name=internal_copied_filegroup_name,
+        srcs=outs,
+        include=include)
+    outs=[internal_copied_filegroup_name]
+
+  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,
+      **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 = _RelativeOutputPath(
+        "python/google/protobuf/internal/%s.py" % m, "python")
+    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..2f67c50
--- /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 google/protobuf/stubs/pbconfig.h $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..1b5b9df
--- /dev/null
+++ b/python/README.md
@@ -0,0 +1,135 @@
+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:
+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
+
+You must set this variable at runtime, before running your program, 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.
diff --git a/python/README.txt b/python/README.txt
deleted file mode 100644
index 04cb176..0000000
--- a/python/README.txt
+++ /dev/null
@@ -1,106 +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.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 google_test
-
-     If you want to build/test c++ implementation, run:
-     $ python setup.py build --cpp_implementation
-     $ python setup.py google_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/protobuf/__init__.py b/python/google/protobuf/__init__.py
index 1345bd5..533821c 100755
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -28,8 +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.
 
-# Needs to stay compatible with Python 2.5 due to GAE.
-#
 # Copyright 2007 Google Inc. All Rights Reserved.
 
-__version__ = '3.0.0a3.dev0'
+__version__ = '3.0.0b2'
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index f7a58ca..5f613c8 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -28,18 +28,15 @@
 # (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)'
 
-from google.protobuf.internal import api_implementation
+import six
 
+from google.protobuf.internal import api_implementation
 
 _USE_C_DESCRIPTORS = False
 if api_implementation.Type() == 'cpp':
@@ -75,7 +72,7 @@
   DescriptorMetaclass = type
 
 
-class DescriptorBase(object):
+class DescriptorBase(six.with_metaclass(DescriptorMetaclass)):
 
   """Descriptors base class.
 
@@ -90,7 +87,6 @@
         avoid some bootstrapping issues.
   """
 
-  __metaclass__ = DescriptorMetaclass
   if _USE_C_DESCRIPTORS:
     # The class, or tuple of classes, that are considered as "virtual
     # subclasses" of this descriptor class.
@@ -222,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.
@@ -245,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|,
@@ -265,7 +261,7 @@
                 file=None, serialized_start=None, serialized_end=None,
                 syntax=None):
       _message.Message._CheckCalledFromGeneratedFile()
-      return _message.Message._GetMessageDescriptor(full_name)
+      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
@@ -296,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:
@@ -321,6 +318,13 @@
       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.
 
@@ -369,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.
@@ -495,9 +500,9 @@
                 has_default_value=True, containing_oneof=None):
       _message.Message._CheckCalledFromGeneratedFile()
       if is_extension:
-        return _message.Message._GetExtensionDescriptor(full_name)
+        return _message.default_pool.FindExtensionByName(full_name)
       else:
-        return _message.Message._GetFieldDescriptor(full_name)
+        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,
@@ -513,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
@@ -528,17 +534,18 @@
     self.containing_oneof = containing_oneof
     if api_implementation.Type() == 'cpp':
       if is_extension:
-        # pylint: disable=protected-access
-        self._cdescriptor = (
-            _message.Message._GetExtensionDescriptor(full_name))
-        # pylint: enable=protected-access
+        self._cdescriptor = _message.default_pool.FindExtensionByName(full_name)
       else:
-        # pylint: disable=protected-access
-        self._cdescriptor = _message.Message._GetFieldDescriptor(full_name)
-        # pylint: enable=protected-access
+        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.
@@ -592,7 +599,7 @@
                 containing_type=None, options=None, file=None,
                 serialized_start=None, serialized_end=None):
       _message.Message._CheckCalledFromGeneratedFile()
-      return _message.Message._GetEnumDescriptor(full_name)
+      return _message.default_pool.FindEnumTypeByName(full_name)
 
   def __init__(self, name, full_name, filename, values,
                containing_type=None, options=None, file=None,
@@ -677,7 +684,7 @@
 
     def __new__(cls, name, full_name, index, containing_type, fields):
       _message.Message._CheckCalledFromGeneratedFile()
-      return _message.Message._GetOneofDescriptor(full_name)
+      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."""
@@ -779,29 +786,33 @@
   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, syntax=None):
+                dependencies=None, syntax=None, pool=None):
       # FileDescriptor() is called from various places, not only from generated
       # files, to register dynamic proto files and messages.
-      # TODO(amauryfa): Expose BuildFile() as a public function and make this
-      # constructor an implementation detail.
       if serialized_pb:
-        # pylint: disable=protected-access2
-        return _message.Message._BuildFile(serialized_pb)
-        # pylint: enable=protected-access
+        # 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, syntax=None):
+               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
@@ -814,9 +825,7 @@
 
     if (api_implementation.Type() == 'cpp' and
         self.serialized_pb is not None):
-      # pylint: disable=protected-access
-      _message.Message._BuildFile(self.serialized_pb)
-      # pylint: enable=protected-access
+      _message.default_pool.AddSerializedFile(self.serialized_pb)
 
   def CopyToProto(self, proto):
     """Copies this to a descriptor_pb2.FileDescriptorProto.
@@ -837,6 +846,27 @@
   return message
 
 
+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.
@@ -864,10 +894,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:
@@ -877,10 +907,8 @@
     else:
       file_descriptor_proto.name = proto_name + '.proto'
 
-    # pylint: disable=protected-access
-    result = _message.Message._BuildFile(
-        file_descriptor_proto.SerializeToString())
-    # pylint: enable=protected-access
+    _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]
@@ -934,5 +962,5 @@
 
   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 b10021e..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.
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index 7e7701f..3e80795 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -57,8 +57,6 @@
 
 __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
@@ -85,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.
 
@@ -113,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.
 
@@ -178,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:
@@ -214,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:
@@ -254,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.
 
@@ -272,6 +321,7 @@
       direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
 
       file_descriptor = descriptor.FileDescriptor(
+          pool=self,
           name=file_proto.name,
           package=file_proto.package,
           syntax=file_proto.syntax,
@@ -320,17 +370,17 @@
                                           file_descriptor, None, scope))
 
         for index, extension_proto in enumerate(file_proto.extension):
-          extension_desc = self.MakeFieldDescriptor(
+          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,
+          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)
+          self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
 
         if file_proto.package:
           desc_proto_prefix = _PrefixWithDot(file_proto.package)
@@ -381,10 +431,11 @@
     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)),
@@ -464,8 +515,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
@@ -506,7 +557,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.
@@ -527,18 +578,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:
@@ -587,10 +638,24 @@
         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
 
@@ -669,3 +734,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
index 6ed2330..dea3f19 100755
--- a/python/google/protobuf/internal/_parameterized.py
+++ b/python/google/protobuf/internal/_parameterized.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,7 +43,7 @@
        (4, 5, 9),
        (1, 1, 3))
     def testAddition(self, op1, op2, result):
-      self.assertEquals(result, op1 + op2)
+      self.assertEqual(result, op1 + op2)
 
 
 Each invocation is a separate test case and properly isolated just
@@ -60,7 +60,7 @@
        {'op1': 4, 'op2': 5, 'result': 9},
     )
     def testAddition(self, op1, op2, result):
-      self.assertEquals(result, op1 + op2)
+      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
@@ -88,7 +88,7 @@
        ('EmptyPrefix', '', 'abc', True),
        ('BothEmpty', '', '', True))
     def testStartsWith(self, prefix, string, result):
-      self.assertEquals(result, strings.startswith(prefix))
+      self.assertEqual(result, strings.startswith(prefix))
 
 Named tests also have the benefit that they can be run individually
 from the command line:
@@ -127,7 +127,7 @@
       c.op1, c.op2, c.result for c in testcases
     )
     def testAddition(self, op1, op2, result):
-      self.assertEquals(result, op1 + op2)
+      self.assertEqual(result, op1 + op2)
 
 
 Single-Argument Test Methods
@@ -149,10 +149,13 @@
 import functools
 import re
 import types
-import unittest
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
 import uuid
 
-from google.apputils import basetest
+import six
 
 ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>')
 _SEPARATOR = uuid.uuid1().hex
@@ -172,13 +175,13 @@
 
 def _NonStringIterable(obj):
   return (isinstance(obj, collections.Iterable) and not
-          isinstance(obj, basestring))
+          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.iteritems())
+                     for argname, value in testcase_params.items())
   elif _NonStringIterable(testcase_params):
     return ', '.join(map(_CleanRepr, testcase_params))
   else:
@@ -260,7 +263,9 @@
       'Cannot add parameters to %s,'
       ' which already has parameterized methods.' % (class_object,))
   class_object._id_suffix = id_suffix = {}
-  for name, obj in class_object.__dict__.items():
+  # 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)
@@ -268,7 +273,7 @@
       _UpdateClassDictForParamTestCase(
           methods, id_suffix, name,
           _ParameterizedTestIter(obj, testcases, naming_type))
-      for name, meth in methods.iteritems():
+      for name, meth in methods.items():
         setattr(class_object, name, meth)
 
 
@@ -380,7 +385,7 @@
     id_suffix[new_name] = getattr(func, '__x_extra_id__', '')
 
 
-class ParameterizedTestCase(basetest.TestCase):
+class ParameterizedTestCase(unittest.TestCase):
   """Base class for test cases using the Parameters decorator."""
   __metaclass__ = TestGeneratorMetaclass
 
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.py b/python/google/protobuf/internal/api_implementation.py
index 8ba4357..ffcf751 100755
--- a/python/google/protobuf/internal/api_implementation.py
+++ b/python/google/protobuf/internal/api_implementation.py
@@ -80,8 +80,8 @@
 
 # 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', '2')
 
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index d976f9e..97cdd84 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -41,6 +41,147 @@
 
 __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):
 
   """Base container class."""
@@ -196,6 +337,8 @@
     # We are presumably comparing against some other sequence type.
     return other == self._values
 
+collections.MutableSequence.register(BaseContainer)
+
 
 class RepeatedCompositeFieldContainer(BaseContainer):
 
@@ -286,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 0f50060..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
@@ -733,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 8970f5c..1baff7d 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,16 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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,18 +51,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.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+    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 11ef61c..f1d6bf9 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,13 @@
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 import os
-import unittest
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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,16 +49,21 @@
 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 test_util
 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 CreatePool(self):
+    return descriptor_pool.DescriptorPool()
 
   def setUp(self):
-    self.pool = descriptor_pool.DescriptorPool()
+    self.pool = self.CreatePool()
     self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
         factory_test1_pb2.DESCRIPTOR.serialized_pb)
     self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
@@ -66,15 +75,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):
@@ -85,17 +94,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):
@@ -106,72 +115,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)
 
@@ -191,35 +200,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)
@@ -227,6 +267,12 @@
     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):
     test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
         descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
@@ -264,6 +310,56 @@
         '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())
+
+
+@unittest.skipIf(api_implementation.Type() != 'cpp',
+                            'explicit tests of the C++ implementation')
+class CppDescriptorPoolTest(DescriptorPoolTest):
+  # TODO(amauryfa): remove when descriptor_pool.DescriptorPool() creates true
+  # C++ descriptor pool object for C++ implementation.
+
+  def CreatePool(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    return _message.DescriptorPool()
+
 
 class ProtoFile(object):
 
@@ -275,8 +371,8 @@
 
   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)
     for name, msg_type in self.messages.items():
@@ -426,12 +522,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)
@@ -442,22 +538,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('.')
@@ -465,7 +563,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)
@@ -476,30 +574,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)
@@ -510,6 +612,76 @@
       pool.FindFileContainingSymbol(
           'protobuf_unittest.TestAllTypes')
 
+  def _GetDescriptorPoolClass(self):
+    # Test with both implementations of descriptor pools.
+    if api_implementation.Type() == 'cpp':
+      # pylint: disable=g-import-not-at-top
+      from google.protobuf.pyext import _message
+      return _message.DescriptorPool
+    else:
+      return descriptor_pool.DescriptorPool
+
+  def testEmptyDescriptorPool(self):
+    # Check that an empty DescriptorPool() contains no message.
+    pool = self._GetDescriptorPoolClass()()
+    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 = self._GetDescriptorPoolClass()()
+    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',
@@ -588,4 +760,4 @@
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
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 50c4dbb..fee09a5 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.
@@ -36,13 +36,18 @@
 
 import sys
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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
 
@@ -52,7 +57,7 @@
 """
 
 
-class DescriptorTest(basetest.TestCase):
+class DescriptorTest(unittest.TestCase):
 
   def setUp(self):
     file_proto = descriptor_pb2.FileDescriptorProto(
@@ -71,9 +76,9 @@
     enum_proto.value.add(name='FOREIGN_BAR', number=5)
     enum_proto.value.add(name='FOREIGN_BAZ', number=6)
 
-    descriptor_pool = symbol_database.Default().pool
-    descriptor_pool.Add(file_proto)
-    self.my_file = descriptor_pool.FindFileByName(file_proto.name)
+    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]
 
@@ -93,6 +98,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')
@@ -389,8 +397,11 @@
   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())
 
-  @basetest.unittest.skipIf(
+  @unittest.skipIf(
       api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
       'Immutability of descriptors is only enforced in v2 implementation')
   def testImmutableCppDescriptor(self):
@@ -403,7 +414,14 @@
       message_descriptor.fields.append(None)
 
 
-class GeneratedDescriptorTest(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):
@@ -421,10 +439,12 @@
     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')
@@ -433,6 +453,10 @@
     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})
 
@@ -455,7 +479,7 @@
     # properties of an immutable abc.Mapping.
     self.assertGreater(len(mapping), 0)  # Sized
     self.assertEqual(len(mapping), len(list(mapping)))  # Iterable
-    if sys.version_info.major >= 3:
+    if sys.version_info >= (3,):
       key, item = next(iter(mapping.items()))
     else:
       key, item = mapping.items()[0]
@@ -464,7 +488,7 @@
     # keys(), iterkeys() &co
     item = (next(iter(mapping.keys())), next(iter(mapping.values())))
     self.assertEqual(item, next(iter(mapping.items())))
-    if sys.version_info.major < 3:
+    if sys.version_info < (3,):
       def CheckItems(seq, iterator):
         self.assertEqual(next(iterator), seq[0])
         self.assertEqual(list(iterator), seq[1:])
@@ -477,6 +501,9 @@
     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.
@@ -493,7 +520,7 @@
     self.assertEqual('FOO', next(values_iter).name)
 
 
-class DescriptorCopyToProtoTest(basetest.TestCase):
+class DescriptorCopyToProtoTest(unittest.TestCase):
   """Tests for CopyTo functions of Descriptor."""
 
   def _AssertProtoEqual(self, actual_proto, expected_class, expected_ascii):
@@ -694,7 +721,7 @@
     #    TEST_SERVICE_ASCII)
 
 
-class MakeDescriptorTest(basetest.TestCase):
+class MakeDescriptorTest(unittest.TestCase):
 
   def testMakeDescriptorWithNestedFields(self):
     file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
@@ -772,8 +799,23 @@
     reformed_descriptor = descriptor.MakeDescriptor(descriptor_proto)
 
     options = reformed_descriptor.GetOptions()
-    self.assertEquals(101,
+    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/generator_test.py b/python/google/protobuf/internal/generator_test.py
index 03361e6..9956da5 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.
@@ -41,12 +41,16 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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 +59,7 @@
 MAX_EXTENSION = 536870912
 
 
-class GeneratorTest(basetest.TestCase):
+class GeneratorTest(unittest.TestCase):
 
   def testNestedMessageDescriptor(self):
     field_name = 'optional_nested_message'
@@ -142,7 +146,7 @@
     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):
@@ -153,7 +157,7 @@
     # 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 +295,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/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
new file mode 100644
index 0000000..49e96a4
--- /dev/null
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -0,0 +1,768 @@
+#! /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
+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.
+    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..2fbe5ea 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,10 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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 +46,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 +84,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 +96,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 +127,9 @@
           '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])
 
 
 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 ed1298a..d03f2d2 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,21 +43,32 @@
 
 __author__ = 'gps@google.com (Gregory P. Smith)'
 
+
+import collections
 import copy
 import math
 import operator
 import pickle
+import six
 import sys
-import unittest
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
 from google.protobuf.internal import _parameterized
+from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf.internal import any_test_pb2
 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
 
+if six.PY3:
+  long = int
+
 # Python pre-2.6 does not have isinf() or isnan() functions, so we have
 # to provide our own.
 def isnan(val):
@@ -75,7 +86,7 @@
 @_parameterized.Parameters(
     (unittest_pb2),
     (unittest_proto3_arena_pb2))
-class MessageTest(basetest.TestCase):
+class MessageTest(unittest.TestCase):
 
   def testBadUtf8String(self, message_module):
     if api_implementation.Type() != 'python':
@@ -126,10 +137,17 @@
     self.assertEqual(unpickled_message, golden_message)
 
   def testPositiveInfinity(self, message_module):
-    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')
+    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')
+
     golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsPosInf(golden_message.optional_float))
@@ -139,10 +157,17 @@
     self.assertEqual(golden_data, golden_message.SerializeToString())
 
   def testNegativeInfinity(self, message_module):
-    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')
+    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))
@@ -305,7 +330,7 @@
   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')
@@ -406,6 +431,31 @@
     self.assertEqual(message.repeated_nested_message[4].bb, 5)
     self.assertEqual(message.repeated_nested_message[5].bb, 6)
 
+  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 = message_module.TestAllTypes()
@@ -424,7 +474,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])
@@ -443,7 +493,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])
@@ -457,7 +507,7 @@
     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'])
@@ -480,7 +530,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
@@ -499,6 +549,12 @@
 
     # 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.
 
@@ -541,6 +597,18 @@
     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'))
@@ -661,9 +729,7 @@
     in the value being converted to a Unicode string."""
     m = message_module.TestAllTypes()
     m.optional_string = str('')
-    self.assertTrue(isinstance(m.optional_string, unicode))
-
-# TODO(haberman): why are these tests Google-internal only?
+    self.assertIsInstance(m.optional_string, six.text_type)
 
   def testLongValuedSlice(self, message_module):
     """It should be possible to use long-valued indicies in slices
@@ -849,7 +915,6 @@
     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.
     """
@@ -887,7 +952,7 @@
 
 
 # Class to test proto2-only features (required, extensions, etc.)
-class Proto2Test(basetest.TestCase):
+class Proto2Test(unittest.TestCase):
 
   def testFieldPresence(self):
     message = unittest_pb2.TestAllTypes()
@@ -1035,64 +1100,131 @@
     self.assertEqual(len(parsing_merge.Extensions[
         unittest_pb2.TestParsingMerge.repeated_ext]), 3)
 
+  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)
+
+    message = unittest_pb2.TestAllTypes(optional_nested_enum=u'BAZ')
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.optional_nested_enum)
+
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(
+          optional_nested_message={'INVALID_NESTED_FIELD': 17})
+
+    with self.assertRaises(TypeError):
+      unittest_pb2.TestAllTypes(
+          optional_nested_message={'bb': 'INVALID_VALUE_TYPE'})
+
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(optional_nested_enum='INVALID_LABEL')
+
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(repeated_nested_enum='FOO')
+
 
 # Class to test proto3-only features/behavior (updated field presence & enums)
-class Proto3Test(basetest.TestCase):
+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")
+      message.HasField('optional_int32')
     with self.assertRaises(ValueError):
-      message.HasField("optional_float")
+      message.HasField('optional_float')
     with self.assertRaises(ValueError):
-      message.HasField("optional_string")
+      message.HasField('optional_string')
     with self.assertRaises(ValueError):
-      message.HasField("optional_bool")
+      message.HasField('optional_bool')
 
     # But we can still test presence of submessage fields.
-    self.assertFalse(message.HasField("optional_nested_message"))
+    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")
+      message.HasField('field_doesnt_exist')
 
     with self.assertRaises(ValueError):
-      message.HasField("repeated_int32")
+      message.HasField('repeated_int32')
     with self.assertRaises(ValueError):
-      message.HasField("repeated_nested_message")
+      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('', 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"))
+    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_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")
+    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('', message.optional_string)
     self.assertEqual(False, message.optional_bool)
     self.assertEqual(0, message.optional_nested_message.bb)
 
@@ -1114,8 +1246,460 @@
     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()
 
-class ValidTypeNamesTest(basetest.TestCase):
+    # 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('abc' in msg.map_string_string)
+    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('', msg.map_string_string['abc'])
+    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('abc' in msg.map_string_string)
+    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 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 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()))
+
+  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)
+
+
+
+class ValidTypeNamesTest(unittest.TestCase):
 
   def assertImportFromName(self, msg, base_name):
     # Parse <type 'module.class_name'> to extra 'some.name' as a string.
@@ -1136,6 +1720,61 @@
     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())
 
 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 161fc5e..1850be5 100644
--- a/python/google/protobuf/internal/missing_enum_values.proto
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -50,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/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
index c74db7e..822ad89 100644
--- a/python/google/protobuf/internal/proto_builder_test.py
+++ b/python/google/protobuf/internal/proto_builder_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,21 +32,28 @@
 
 """Tests for google.protobuf.proto_builder."""
 
-from google.apputils import basetest
-
+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(basetest.TestCase):
+class ProtoBuilderTest(unittest.TestCase):
 
   def setUp(self):
-    self._fields = {
-        'foo': descriptor_pb2.FieldDescriptorProto.TYPE_INT64,
-        'bar': descriptor_pb2.FieldDescriptorProto.TYPE_STRING,
-        }
+    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."""
@@ -59,6 +66,17 @@
     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()
@@ -74,4 +92,4 @@
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 6ad0f90..87f6066 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,14 @@
 
 __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
+import six.moves.copyreg 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 +65,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 +265,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:
@@ -228,9 +323,16 @@
     if field_descriptor.containing_oneof is not None:
       oneof_descriptor = field_descriptor
 
-    field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
-        field_descriptor.number, is_repeated, is_packed,
-        field_descriptor, field_descriptor._default_constructor)
+    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)
 
@@ -245,7 +347,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
 
@@ -265,6 +367,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.
 
@@ -279,6 +401,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' % (
@@ -303,9 +428,10 @@
     message_type = field.message_type
     def MakeSubMessageDefault(message):
       result = message_type._concrete_class()
-      result._SetListener(message._listener_for_children)
-      if field.containing_oneof:
-        message._UpdateOneofState(field)
+      result._SetListener(
+          _OneofListener(message, field)
+          if field.containing_oneof is not None
+          else message._listener_for_children)
       return result
     return MakeSubMessageDefault
 
@@ -324,12 +450,27 @@
     exc = TypeError('%s for field %s.%s' % (str(exc), message_name, field_name))
 
   # re-raise possibly-amended exception with original traceback:
-  raise type(exc), exc, sys.exc_info()[2]
+  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
@@ -344,7 +485,7 @@
     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'" %
@@ -352,19 +493,37 @@
       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)
+        new_val = field_value
+        if isinstance(field_value, dict):
+          new_val = field.message_type._concrete_class(**field_value)
         try:
-          copy.MergeFrom(field_value)
+          copy.MergeFrom(new_val)
         except TypeError:
           _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
         self._fields[field] = copy
       else:
+        if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+          field_value = _GetIntegerEnumValue(field.enum_type, field_value)
         try:
           setattr(self, field_name, field_value)
         except TypeError:
@@ -387,7 +546,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):
@@ -542,21 +702,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
@@ -583,7 +733,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)
 
@@ -638,7 +788,7 @@
   """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
 
@@ -702,9 +852,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.
@@ -758,6 +914,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()."""
@@ -769,6 +957,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
 
@@ -790,6 +984,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()."""
 
@@ -894,7 +1095,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
@@ -961,6 +1162,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:
@@ -996,16 +1200,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
 
@@ -1027,7 +1241,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:
@@ -1042,8 +1256,6 @@
             # Construct a new object to represent this field.
             field_value = field._default_constructor(self)
             fields[field] = field_value
-            if field.containing_oneof:
-              self._UpdateOneofState(field)
           field_value.MergeFrom(value)
       else:
         self._fields[field] = value
@@ -1087,6 +1299,7 @@
   _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)
@@ -1097,6 +1310,7 @@
   _AddMergeFromMethod(cls)
   _AddWhichOneofMethod(message_descriptor, cls)
 
+
 def _AddPrivateHelperMethods(message_descriptor, cls):
   """Adds implementation of private helper methods to cls."""
 
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index a62d984..752f2f5 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
@@ -38,9 +38,13 @@
 import copy
 import gc
 import operator
+import six
 import struct
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
@@ -52,6 +56,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
@@ -102,7 +107,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))
@@ -128,10 +133,10 @@
         repeated_bool=[True, False, False],
         repeated_string=["optional_string"])
 
-    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))
 
   def testRepeatedCompositeConstructor(self):
     # Constructor with only repeated composite types should succeed.
@@ -150,18 +155,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)],
@@ -186,15 +191,15 @@
 
     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)],
@@ -222,18 +227,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.
@@ -467,7 +472,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(
@@ -609,14 +614,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.
@@ -624,10 +633,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):
@@ -753,18 +762,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()
@@ -803,7 +812,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.
@@ -894,7 +903,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__,
@@ -1006,9 +1015,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'))
@@ -1048,14 +1056,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()
@@ -1173,7 +1180,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
@@ -1497,18 +1504,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()
@@ -1619,7 +1626,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):
@@ -1661,14 +1668,14 @@
                       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 'bytes' object which contains non-UTF-8.
     self.assertRaises(ValueError,
@@ -1682,8 +1689,8 @@
     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 +1710,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 +1745,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()
@@ -1792,23 +1798,11 @@
     # Just check the default value.
     self.assertEqual(57, msg.inner.value)
 
-  @basetest.unittest.skipIf(
-      api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
-      'CPPv2-specific test')
-  def testBadArguments(self):
-    # Some of these assertions used to segfault.
-    from google.protobuf.pyext import _message
-    self.assertRaises(TypeError, _message.Message._GetFieldDescriptor, 3)
-    self.assertRaises(TypeError, _message.Message._GetExtensionDescriptor, 42)
-    self.assertRaises(TypeError,
-                      unittest_pb2.TestAllTypes().__getattribute__, 42)
-
-
 #  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()
@@ -1824,7 +1818,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."""
 
@@ -1910,7 +1904,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()
@@ -1943,7 +1937,7 @@
     self.assertEqual(first_proto, second_proto)
 
 
-class MutualRecursionEqualityTest(basetest.TestCase):
+class MutualRecursionEqualityTest(unittest.TestCase):
 
   def testEqualityWithMutualRecursion(self):
     first_proto = unittest_pb2.TestMutualRecursionA()
@@ -1955,7 +1949,7 @@
     self.assertEqual(first_proto, second_proto)
 
 
-class ByteSizeTest(basetest.TestCase):
+class ByteSizeTest(unittest.TestCase):
 
   def setUp(self):
     self.proto = unittest_pb2.TestAllTypes()
@@ -2251,7 +2245,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()
@@ -2318,7 +2312,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()
@@ -2395,13 +2389,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).
@@ -2413,27 +2409,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))
@@ -2446,39 +2449,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()
@@ -2763,9 +2766,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)
@@ -2802,10 +2806,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()
@@ -2824,14 +2828,14 @@
     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):
 
-  @basetest.unittest.skipIf(
+  @unittest.skipIf(
       api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
       'C++ implementation requires a call to MakeDescriptor()')
   def testMakeClassWithNestedDescriptor(self):
@@ -2914,13 +2918,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 = (
@@ -2963,4 +2973,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 d066ae7..98614b7 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,16 @@
 
 __author__ = 'petar@google.com (Petar Petrov)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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 +83,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
@@ -125,12 +128,11 @@
     # 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..0cb935a 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,32 @@
 
 """Tests for google.protobuf.symbol_database."""
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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 +72,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_util.py b/python/google/protobuf/internal/test_util.py
index d84e383..ac88fa8 100755
--- a/python/google/protobuf/internal/test_util.py
+++ b/python/google/protobuf/internal/test_util.py
@@ -75,7 +75,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
@@ -109,7 +110,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
@@ -140,7 +142,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
@@ -396,7 +399,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'))
@@ -430,7 +434,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)
@@ -463,7 +468,8 @@
   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))
@@ -491,7 +497,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)
@@ -521,7 +528,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)
@@ -594,6 +602,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 '
diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py
index db0222b..338a287 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,10 @@
 
 """Tests for google.protobuf.text_encoding."""
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
 from google.protobuf import text_encoding
 
 TEST_VALUES = [
@@ -50,19 +53,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 7d5813f..0e14556 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,20 +34,41 @@
 
 __author__ = 'kenton@google.com (Kenton Varda)'
 
-import re
 
-from google.apputils import basetest
+import re
+import six
+import string
+
+try:
+  import unittest2 as unittest
+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.internal import message_set_extensions_pb2
 from google.protobuf import text_format
 
+
+# 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(basetest.TestCase):
+class TextFormatBase(unittest.TestCase):
 
   def ReadGolden(self, golden_filename):
     with test_util.GoldenFile(golden_filename) as f:
@@ -59,7 +80,7 @@
     self.assertMultiLineEqual(text, ''.join(golden_lines))
 
   def CompareToGoldenText(self, text, golden_text):
-    self.assertMultiLineEqual(text, golden_text)
+    self.assertEqual(text, golden_text)
 
   def RemoveRedundantZeros(self, text):
     # Some platforms print 1e+5 as 1e+005.  This is fine, but we need to remove
@@ -98,7 +119,7 @@
         'repeated_string: "\\303\\274\\352\\234\\237"\n')
 
   def testPrintExoticUnicodeSubclass(self, message_module):
-    class UnicodeSub(unicode):
+    class UnicodeSub(six.text_type):
       pass
     message = message_module.TestAllTypes()
     message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
@@ -170,7 +191,7 @@
     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(
@@ -178,7 +199,7 @@
     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_module):
@@ -188,7 +209,7 @@
     self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n')
     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, message_module):
@@ -215,13 +236,13 @@
     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_module):
     message = message_module.ForeignMessage()
@@ -280,11 +301,24 @@
     self.assertEqual(u'one', message.repeated_string[0])
     self.assertEqual(u'two', message.repeated_string[1])
 
+  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 testParseEmptyText(self, message_module):
     message = message_module.TestAllTypes()
     text = ''
     text_format.Parse(text, message)
-    self.assertEquals(message_module.TestAllTypes(), message)
+    self.assertEqual(message_module.TestAllTypes(), message)
 
   def testParseInvalidUtf8(self, message_module):
     message = message_module.TestAllTypes()
@@ -294,7 +328,7 @@
   def testParseSingleWord(self, message_module):
     message = message_module.TestAllTypes()
     text = 'foo'
-    self.assertRaisesRegexp(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
          r'"foo".'),
@@ -303,41 +337,16 @@
   def testParseUnknownField(self, message_module):
     message = message_module.TestAllTypes()
     text = 'unknown_field: 8\n'
-    self.assertRaisesRegexp(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
          r'"unknown_field".'),
         text_format.Parse, text, message)
 
-  def testParseGroupNotClosed(self, message_module):
-    message = message_module.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_module):
-    message = message_module.TestAllTypes()
-    text = 'OptionalGroup: {}'
-    text_format.Parse(text, message)
-    self.assertTrue(message.HasField('optionalgroup'))
-
-    message.Clear()
-
-    message = message_module.TestAllTypes()
-    text = 'OptionalGroup: <>'
-    text_format.Parse(text, message)
-    self.assertTrue(message.HasField('optionalgroup'))
-
   def testParseBadEnumValue(self, message_module):
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: BARR'
-    self.assertRaisesRegexp(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
          r'has no value named BARR.'),
@@ -345,7 +354,7 @@
 
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: 100'
-    self.assertRaisesRegexp(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
          r'has no value with number 100.'),
@@ -354,7 +363,7 @@
   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)
@@ -408,6 +417,14 @@
 # Ideally the schemas would be made more similar so these tests could pass.
 class OnlyWorksWithProto2RightNowTests(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 testParseGolden(self):
     golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt'))
     parsed_message = unittest_pb2.TestAllTypes()
@@ -416,7 +433,7 @@
 
     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()
@@ -469,10 +486,81 @@
 
     message = unittest_pb2.TestAllTypes()
     test_util.SetAllFields(message)
-    self.assertEquals(message, parsed_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))
 
 
-# Tests of proto2-only features (MessageSet and extensions).
+# Tests of proto2-only features (MessageSet, extensions, etc.).
 class Proto2Tests(TextFormatBase):
 
   def testPrintMessageSet(self):
@@ -492,6 +580,15 @@
         '  }\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 testPrintMessageSetAsOneLine(self):
     message = unittest_mset_pb2.TestMessageSetContainer()
     ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
@@ -529,8 +626,8 @@
     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)
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
 
   def testPrintAllExtensions(self):
     message = unittest_pb2.TestAllExtensions()
@@ -555,7 +652,7 @@
 
     message = unittest_pb2.TestAllExtensions()
     test_util.SetAllExtensions(message)
-    self.assertEquals(message, parsed_message)
+    self.assertEqual(message, parsed_message)
 
   def testParseAllExtensions(self):
     message = unittest_pb2.TestAllExtensions()
@@ -566,15 +663,125 @@
     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'
+            '    [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'
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         '1:2 : Extension "unknown_extension" not registered.',
         text_format.Parse, text, message)
     message = unittest_pb2.TestAllTypes()
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
          'extensions.'),
@@ -593,7 +800,7 @@
     message = unittest_pb2.TestAllExtensions()
     text = ('[protobuf_unittest.optional_int32_extension]: 42 '
             '[protobuf_unittest.optional_int32_extension]: 67')
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
          'should not have multiple '
@@ -604,7 +811,7 @@
     message = unittest_pb2.TestAllTypes()
     text = ('optional_nested_message { bb: 1 } '
             'optional_nested_message { bb: 2 }')
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
          'should not have multiple "bb" fields.'),
@@ -614,14 +821,77 @@
     message = unittest_pb2.TestAllTypes()
     text = ('optional_int32: 42 '
             'optional_int32: 67')
-    self.assertRaisesWithLiteralMatch(
+    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)
 
-class TokenizerTest(basetest.TestCase):
+  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'
@@ -766,4 +1036,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 76c056c..f30ca6a 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
@@ -117,9 +116,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)
@@ -129,6 +128,9 @@
     proposed_value = self._TYPE(proposed_value)
     return proposed_value
 
+  def DefaultValue(self):
+    return 0
+
 
 class EnumValueChecker(object):
 
@@ -138,14 +140,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):
 
@@ -155,9 +160,9 @@
   """
 
   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 valid UTF-8 data.
@@ -171,6 +176,9 @@
                          (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
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
index 59f9ae4..9685b8b 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,18 +35,28 @@
 
 __author__ = 'bohdank@google.com (Bohdan Koval)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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
@@ -83,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
@@ -100,13 +110,6 @@
     new_raw.MergeFromString(reserialized)
     self.assertEqual(raw, new_raw)
 
-  # C++ implementation for proto2 does not currently take into account unknown
-  # fields when checking equality.
-  #
-  # TODO(haberman): fix this.
-  @basetest.unittest.skipIf(
-      api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
-      'C++ implementation does not expose unknown fields to Python')
   def testEquals(self):
     message = unittest_pb2.TestEmptyMessage()
     message.ParseFromString(self.all_fields_data)
@@ -117,10 +120,7 @@
     self.assertNotEqual(self.empty_message, message)
 
 
-@basetest.unittest.skipIf(
-    api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
-    'C++ implementation does not expose unknown fields to Python')
-class UnknownFieldsAccessorsTest(basetest.TestCase):
+class UnknownFieldsAccessorsTest(unittest.TestCase):
 
   def setUp(self):
     self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
@@ -129,7 +129,14 @@
     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
+    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]
@@ -142,30 +149,37 @@
         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)
@@ -173,7 +187,7 @@
   def testCopyFrom(self):
     message = unittest_pb2.TestEmptyMessage()
     message.CopyFrom(self.empty_message)
-    self.assertEqual(self.unknown_fields, message._unknown_fields)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
 
   def testMergeFrom(self):
     message = unittest_pb2.TestAllTypes()
@@ -187,28 +201,27 @@
     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)
+    # 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()
-    self.assertEqual(0, len(self.empty_message._unknown_fields))
+    # 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(self.empty_message._unknown_fields,
-                     message._unknown_fields)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
 
 
-
-@basetest.unittest.skipIf(
-    api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
-    'C++ implementation does not expose unknown fields to Python')
-class UnknownEnumValuesTest(basetest.TestCase):
+class UnknownEnumValuesTest(unittest.TestCase):
 
   def setUp(self):
     self.descriptor = missing_enum_values_pb2.TestEnumValues.DESCRIPTOR
@@ -227,7 +240,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]
@@ -241,15 +261,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)
@@ -261,4 +297,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..d35fcc5
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -0,0 +1,720 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 Is(self, descriptor):
+    """Checks if this Any represents the given protobuf type."""
+    # Only last part is to be used: b/25630112
+    return self.type_url.split('/')[-1] == 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..6acbee2
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -0,0 +1,636 @@
+#! /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
+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 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..f659d18 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,15 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest
+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 +253,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..23382bd
--- /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
+  js = {}
+  for key in fields.keys():
+    js[key] = _ValueMessageToJsonObject(fields[key])
+  return js
+
+
+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_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
index 1fa28f1..736caed 100644
--- a/python/google/protobuf/proto_builder.py
+++ b/python/google/protobuf/proto_builder.py
@@ -30,6 +30,10 @@
 
 """Dynamic Protobuf class creator."""
 
+try:
+    from collections import OrderedDict
+except ImportError:
+    from ordereddict import OrderedDict  #PY26
 import hashlib
 import os
 
@@ -44,7 +48,7 @@
     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.
+    A class, for the type identified by full_name.
   Raises:
     KeyError, if the proto is not found in the factory's descriptor pool.
   """
@@ -53,46 +57,74 @@
   return proto_cls
 
 
-def MakeSimpleProtoClass(fields, full_name, pool=None):
+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.
-    full_name: str, the fully-qualified name of the proto type.
+    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)
-  try:
-    proto_cls = _GetMessageFromFactory(factory, full_name)
-    return proto_cls
-  except KeyError:
-    # The factory's DescriptorPool doesn't know about this class yet.
-    pass
+
+  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 sorted(fields.items()):
-    fields_hash.update(f_name.encode('utf8'))
-    fields_hash.update(str(f_type).encode('utf8'))
+  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(sorted(fields.items()), 1):
+  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
-
-  factory.pool.Add(file_proto)
-  return _GetMessageFromFactory(factory, full_name)
+  return file_proto
diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py
index 037bb72..b215211 100644
--- a/python/google/protobuf/pyext/cpp_message.py
+++ b/python/google/protobuf/pyext/cpp_message.py
@@ -37,21 +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):
-  """Finalizes the creation of a message class."""
-  cls.AddDescriptors(message_descriptor)
+  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'
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index e77d0bb..a875a7b 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -43,8 +43,6 @@
 #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
@@ -64,6 +62,14 @@
 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());
 }
@@ -149,6 +155,24 @@
 
 // Helper functions for descriptor objects.
 
+// 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();
+}
+
 // Converts options into a Python protobuf, and cache the result.
 //
 // This is a bit tricky because options can contain extension fields defined in
@@ -158,8 +182,13 @@
 // 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 =
-      GetDescriptorPool()->descriptor_options;
+      pool->descriptor_options;
   // First search in the cache.
   if (descriptor_options->find(descriptor) != descriptor_options->end()) {
     PyObject *value = (*descriptor_options)[descriptor];
@@ -172,7 +201,15 @@
   const Message& options(descriptor->options());
   const Descriptor *message_type = options.GetDescriptor();
   PyObject* message_class(cdescriptor_pool::GetMessageClass(
-      GetDescriptorPool(), message_type));
+      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());
@@ -182,6 +219,12 @@
   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();
@@ -194,8 +237,7 @@
     options.SerializeToString(&serialized);
     io::CodedInputStream input(
         reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
-    input.SetExtensionRegistry(GetDescriptorPool()->pool,
-                               cmessage::GetMessageFactory());
+    input.SetExtensionRegistry(pool->pool, pool->message_factory);
     bool success = cmsg->message->MergePartialFromCodedStream(&input);
     if (!success) {
       PyErr_Format(PyExc_ValueError, "Error parsing Options message");
@@ -204,8 +246,8 @@
   }
 
   // Cache the result.
-  Py_INCREF(value);
-  (*GetDescriptorPool()->descriptor_options)[descriptor] = value.get();
+  Py_INCREF(value.get());
+  (*pool->descriptor_options)[descriptor] = value.get();
 
   return value.release();
 }
@@ -239,6 +281,9 @@
   // 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;
 
 
@@ -257,8 +302,16 @@
 // 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.
-PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor) {
+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;
@@ -266,8 +319,8 @@
 
   // See if the object is in the map of interned descriptors
   hash_map<const void*, PyObject*>::iterator it =
-      GetDescriptorPool()->interned_descriptors->find(descriptor);
-  if (it != GetDescriptorPool()->interned_descriptors->end()) {
+      interned_descriptors.find(descriptor);
+  if (it != interned_descriptors.end()) {
     GOOGLE_DCHECK(Py_TYPE(it->second) == type);
     Py_INCREF(it->second);
     return it->second;
@@ -279,16 +332,32 @@
     return NULL;
   }
   py_descriptor->descriptor = descriptor;
+
   // and cache it.
-  GetDescriptorPool()->interned_descriptors->insert(
+  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
-  GetDescriptorPool()->interned_descriptors->erase(self->descriptor);
+  interned_descriptors.erase(self->descriptor);
+  Py_CLEAR(self->pool);
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 
@@ -298,9 +367,7 @@
 
 PyTypeObject PyBaseDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.internal._message."
-  "DescriptorBase",                     // tp_name
+  FULL_MODULE_NAME ".DescriptorBase",   // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   (destructor)Dealloc,                  // tp_dealloc
@@ -357,31 +424,31 @@
 }
 
 static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
-  return PyFileDescriptor_New(_GetDescriptor(self)->file());
+  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.
   PyObject* concrete_class(cdescriptor_pool::GetMessageClass(
-      GetDescriptorPool(), _GetDescriptor(self)));
+      GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()),
+      _GetDescriptor(self)));
   Py_XINCREF(concrete_class);
   return concrete_class;
 }
 
-static int SetConcreteClass(PyBaseDescriptor *self, PyObject *value,
-                            void *closure) {
-  // This attribute is also set from reflection.py. Check that it's actually a
-  // no-op.
-  if (value != cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), _GetDescriptor(self))) {
-    PyErr_SetString(PyExc_AttributeError, "Cannot change _concrete_class");
-  }
-  return 0;
-}
-
 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));
 }
@@ -452,7 +519,7 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -515,29 +582,36 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "Last name", NULL},
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("_concrete_class"), (getter)GetConcreteClass, (setter)SetConcreteClass, "concrete class", NULL},
-  { C("file"), (getter)GetFile, NULL, "File descriptor", NULL},
+  { "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"},
 
-  { C("fields"), (getter)GetFieldsSeq, NULL, "Fields sequence", NULL},
-  { C("fields_by_name"), (getter)GetFieldsByName, NULL, "Fields by name", NULL},
-  { C("fields_by_number"), (getter)GetFieldsByNumber, NULL, "Fields by number", NULL},
-  { C("nested_types"), (getter)GetNestedTypesSeq, NULL, "Nested types sequence", NULL},
-  { C("nested_types_by_name"), (getter)GetNestedTypesByName, NULL, "Nested types by name", NULL},
-  { C("extensions"), (getter)GetExtensions, NULL, "Extensions Sequence", NULL},
-  { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL},
-  { C("extension_ranges"), (getter)GetExtensionRanges, NULL, "Extension ranges", NULL},
-  { C("enum_types"), (getter)GetEnumsSeq, NULL, "Enum sequence", NULL},
-  { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enum types by name", NULL},
-  { C("enum_values_by_name"), (getter)GetEnumValuesByName, NULL, "Enum values by name", NULL},
-  { C("oneofs_by_name"), (getter)GetOneofsByName, NULL, "Oneofs by name", NULL},
-  { C("oneofs"), (getter)GetOneofsSeq, NULL, "Oneofs by name", NULL},
-  { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
-  { C("is_extendable"), (getter)IsExtendable, (setter)NULL, NULL, NULL},
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
-  { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL},
+  { "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}
 };
 
@@ -552,9 +626,7 @@
 
 PyTypeObject PyMessageDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  C("google.protobuf.internal._message."
-    "MessageDescriptor"),      // tp_name
+  FULL_MODULE_NAME ".MessageDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -573,7 +645,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Message Descriptor"),            // tp_doc
+  "A Message Descriptor",               // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -586,10 +658,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyMessageDescriptor_New(
+PyObject* PyMessageDescriptor_FromDescriptor(
     const Descriptor* message_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyMessageDescriptor_Type, message_descriptor);
+      &PyMessageDescriptor_Type, message_descriptor, NULL);
 }
 
 const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) {
@@ -617,6 +689,10 @@
   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());
 }
@@ -715,7 +791,7 @@
 static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) {
   const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type();
   if (enum_type) {
-    return PyEnumDescriptor_New(enum_type);
+    return PyEnumDescriptor_FromDescriptor(enum_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -728,7 +804,7 @@
 static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) {
   const Descriptor* message_type = _GetDescriptor(self)->message_type();
   if (message_type) {
-    return PyMessageDescriptor_New(message_type);
+    return PyMessageDescriptor_FromDescriptor(message_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -743,7 +819,7 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -758,7 +834,7 @@
   const Descriptor* extension_scope =
       _GetDescriptor(self)->extension_scope();
   if (extension_scope) {
-    return PyMessageDescriptor_New(extension_scope);
+    return PyMessageDescriptor_FromDescriptor(extension_scope);
   } else {
     Py_RETURN_NONE;
   }
@@ -768,7 +844,7 @@
   const OneofDescriptor* containing_oneof =
       _GetDescriptor(self)->containing_oneof();
   if (containing_oneof) {
-    return PyOneofDescriptor_New(containing_oneof);
+    return PyOneofDescriptor_FromDescriptor(containing_oneof);
   } else {
     Py_RETURN_NONE;
   }
@@ -803,26 +879,31 @@
 
 
 static PyGetSetDef Getters[] = {
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("name"), (getter)GetName, NULL, "Unqualified name", NULL},
-  { C("type"), (getter)GetType, NULL, "C++ Type", NULL},
-  { C("cpp_type"), (getter)GetCppType, NULL, "C++ Type", NULL},
-  { C("label"), (getter)GetLabel, NULL, "Label", NULL},
-  { C("number"), (getter)GetNumber, NULL, "Number", NULL},
-  { C("index"), (getter)GetIndex, NULL, "Index", NULL},
-  { C("default_value"), (getter)GetDefaultValue, NULL, "Default Value", NULL},
-  { C("has_default_value"), (getter)HasDefaultValue, NULL, NULL, NULL},
-  { C("is_extension"), (getter)IsExtension, NULL, "ID", NULL},
-  { C("id"), (getter)GetID, NULL, "ID", NULL},
-  { C("_cdescriptor"), (getter)GetCDescriptor, NULL, "HAACK REMOVE ME", NULL},
+  { "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"},
 
-  { C("message_type"), (getter)GetMessageType, (setter)SetMessageType, "Message type", NULL},
-  { C("enum_type"), (getter)GetEnumType, (setter)SetEnumType, "Enum type", NULL},
-  { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
-  { C("extension_scope"), (getter)GetExtensionScope, (setter)NULL, "Extension scope", NULL},
-  { C("containing_oneof"), (getter)GetContainingOneof, (setter)SetContainingOneof, "Containing oneof", NULL},
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+  { "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}
 };
 
@@ -835,8 +916,7 @@
 
 PyTypeObject PyFieldDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.FieldDescriptor"),        // tp_name
+  FULL_MODULE_NAME ".FieldDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -855,7 +935,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Field Descriptor"),              // tp_doc
+  "A Field Descriptor",                 // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -868,10 +948,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyFieldDescriptor_New(
+PyObject* PyFieldDescriptor_FromDescriptor(
     const FieldDescriptor* field_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyFieldDescriptor_Type, field_descriptor);
+      &PyFieldDescriptor_Type, field_descriptor, NULL);
 }
 
 const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) {
@@ -900,7 +980,7 @@
 }
 
 static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
-  return PyFileDescriptor_New(_GetDescriptor(self)->file());
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
 }
 
 static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) {
@@ -919,7 +999,7 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -964,16 +1044,19 @@
 };
 
 static PyGetSetDef Getters[] = {
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("name"), (getter)GetName, NULL, "last name", NULL},
-  { C("file"), (getter)GetFile, NULL, "File descriptor", NULL},
-  { C("values"), (getter)GetEnumvaluesSeq, NULL, "values", NULL},
-  { C("values_by_name"), (getter)GetEnumvaluesByName, NULL, "Enumvalues by name", NULL},
-  { C("values_by_number"), (getter)GetEnumvaluesByNumber, NULL, "Enumvalues by number", NULL},
+  { "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"},
 
-  { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
   {NULL}
 };
 
@@ -981,9 +1064,7 @@
 
 PyTypeObject PyEnumDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  C("google.protobuf.internal._message."
-    "EnumDescriptor"),                  // tp_name
+  FULL_MODULE_NAME ".EnumDescriptor",   // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -1002,7 +1083,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Enum Descriptor"),               // tp_doc
+  "A Enum Descriptor",                  // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1015,10 +1096,19 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyEnumDescriptor_New(
+PyObject* PyEnumDescriptor_FromDescriptor(
     const EnumDescriptor* enum_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyEnumDescriptor_Type, enum_descriptor);
+      &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 {
@@ -1042,7 +1132,7 @@
 }
 
 static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
-  return PyEnumDescriptor_New(_GetDescriptor(self)->type());
+  return PyEnumDescriptor_FromDescriptor(_GetDescriptor(self)->type());
 }
 
 static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
@@ -1069,13 +1159,13 @@
 
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "name", NULL},
-  { C("number"), (getter)GetNumber, NULL, "number", NULL},
-  { C("index"), (getter)GetIndex, NULL, "index", NULL},
-  { C("type"), (getter)GetType, NULL, "index", NULL},
+  { "name", (getter)GetName, NULL, "name"},
+  { "number", (getter)GetNumber, NULL, "number"},
+  { "index", (getter)GetIndex, NULL, "index"},
+  { "type", (getter)GetType, NULL, "index"},
 
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
   {NULL}
 };
 
@@ -1088,8 +1178,7 @@
 
 PyTypeObject PyEnumValueDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.EnumValueDescriptor"),    // tp_name
+  FULL_MODULE_NAME ".EnumValueDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -1108,7 +1197,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A EnumValue Descriptor"),          // tp_doc
+  "A EnumValue Descriptor",             // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1121,10 +1210,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyEnumValueDescriptor_New(
+PyObject* PyEnumValueDescriptor_FromDescriptor(
     const EnumValueDescriptor* enumvalue_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyEnumValueDescriptor_Type, enumvalue_descriptor);
+      &PyEnumValueDescriptor_Type, enumvalue_descriptor, NULL);
 }
 
 namespace file_descriptor {
@@ -1139,6 +1228,13 @@
   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());
 }
@@ -1218,18 +1314,21 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "name", NULL},
-  { C("package"), (getter)GetPackage, NULL, "package", NULL},
-  { C("serialized_pb"), (getter)GetSerializedPb, NULL, NULL, NULL},
-  { C("message_types_by_name"), (getter)GetMessageTypesByName, NULL, "Messages by name", NULL},
-  { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enums by name", NULL},
-  { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL},
-  { C("dependencies"), (getter)GetDependencies, NULL, "Dependencies", NULL},
-  { C("public_dependencies"), (getter)GetPublicDependencies, NULL, "Dependencies", NULL},
+  { "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"},
 
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
-  { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
   {NULL}
 };
 
@@ -1243,11 +1342,10 @@
 
 PyTypeObject PyFileDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.FileDescriptor"),         // tp_name
+  FULL_MODULE_NAME ".FileDescriptor",   // tp_name
   sizeof(PyFileDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
-  (destructor)file_descriptor::Dealloc, // tp_dealloc
+  (destructor)file_descriptor::Dealloc,  // tp_dealloc
   0,                                    // tp_print
   0,                                    // tp_getattr
   0,                                    // tp_setattr
@@ -1263,7 +1361,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A File Descriptor"),               // tp_doc
+  "A File Descriptor",                  // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1279,32 +1377,46 @@
   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
 };
 
-PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyFileDescriptor_Type, file_descriptor);
+PyObject* PyFileDescriptor_FromDescriptor(
+    const FileDescriptor* file_descriptor) {
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor,
+                                                         NULL);
 }
 
-PyObject* PyFileDescriptor_NewWithPb(
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
     const FileDescriptor* file_descriptor, PyObject *serialized_pb) {
-  PyObject* py_descriptor = PyFileDescriptor_New(file_descriptor);
+  bool was_created;
+  PyObject* py_descriptor = descriptor::NewInternedDescriptor(
+      &PyFileDescriptor_Type, file_descriptor, &was_created);
   if (py_descriptor == NULL) {
     return NULL;
   }
-  if (serialized_pb != 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 py_descriptor;
 }
 
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<const FileDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
 namespace oneof_descriptor {
 
 // Unchecked accessor to the C++ pointer.
@@ -1333,19 +1445,19 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
 }
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "Name", NULL},
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("index"), (getter)GetIndex, NULL, "Index", NULL},
+  { "name", (getter)GetName, NULL, "Name"},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "index", (getter)GetIndex, NULL, "Index"},
 
-  { C("containing_type"), (getter)GetContainingType, NULL, "Containing type", NULL},
-  { C("fields"), (getter)GetFields, NULL, "Fields", NULL},
+  { "containing_type", (getter)GetContainingType, NULL, "Containing type"},
+  { "fields", (getter)GetFields, NULL, "Fields"},
   {NULL}
 };
 
@@ -1353,8 +1465,7 @@
 
 PyTypeObject PyOneofDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.OneofDescriptor"),        // tp_name
+  FULL_MODULE_NAME ".OneofDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -1373,7 +1484,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Oneof Descriptor"),              // tp_doc
+  "A Oneof Descriptor",                 // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1386,10 +1497,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyOneofDescriptor_New(
+PyObject* PyOneofDescriptor_FromDescriptor(
     const OneofDescriptor* oneof_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyOneofDescriptor_Type, oneof_descriptor);
+      &PyOneofDescriptor_Type, oneof_descriptor, NULL);
 }
 
 // Add a enum values to a type dictionary.
@@ -1401,7 +1512,8 @@
     if (obj == NULL) {
       return false;
     }
-    if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj) < 0) {
+    if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj.get()) <
+        0) {
       return false;
     }
   }
@@ -1410,7 +1522,7 @@
 
 static bool AddIntConstant(PyTypeObject *type, const char* name, int value) {
   ScopedPyObjectPtr obj(PyInt_FromLong(value));
-  if (PyDict_SetItemString(type->tp_dict, name, obj) < 0) {
+  if (PyDict_SetItemString(type->tp_dict, name, obj.get()) < 0) {
     return false;
   }
   return true;
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index ba6e729..eb99df1 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -48,27 +48,32 @@
 extern PyTypeObject PyFileDescriptor_Type;
 extern PyTypeObject PyOneofDescriptor_Type;
 
-// Return a new reference to a Descriptor object.
+// 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.
-PyObject* PyMessageDescriptor_New(const Descriptor* descriptor);
-PyObject* PyFieldDescriptor_New(const FieldDescriptor* descriptor);
-PyObject* PyEnumDescriptor_New(const EnumDescriptor* descriptor);
-PyObject* PyEnumValueDescriptor_New(const EnumValueDescriptor* descriptor);
-PyObject* PyOneofDescriptor_New(const OneofDescriptor* descriptor);
-PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor);
+// Returns a new reference.
+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);
 
 // Alternate constructor of PyFileDescriptor, used when we already have a
 // serialized FileDescriptorProto that can be cached.
 // Returns a new reference.
-PyObject* PyFileDescriptor_NewWithPb(const FileDescriptor* file_descriptor,
-                                     PyObject* serialized_pb);
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
+    const FileDescriptor* file_descriptor, PyObject* serialized_pb);
 
 // 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);
 
 // Returns the raw C++ pointer.
 const void* PyDescriptor_AsVoidPtr(PyObject* obj);
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index 06edebf..e505d81 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -79,9 +79,12 @@
 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);
 
@@ -95,6 +98,9 @@
   // 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;
@@ -102,6 +108,9 @@
   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.
@@ -125,6 +134,7 @@
   enum ContainerKind {
     KIND_SEQUENCE,
     KIND_BYNAME,
+    KIND_BYCAMELCASENAME,
     KIND_BYNUMBER,
   } kind;
 };
@@ -172,6 +182,23 @@
             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);
@@ -203,6 +230,12 @@
         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);
@@ -276,6 +309,9 @@
     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;
@@ -319,7 +355,7 @@
       if (value2 == NULL) {
         return -1;
       }
-      int cmp = PyObject_RichCompareBool(value1, value2, Py_EQ);
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
       if (cmp != 1)  // error or not equal
           return cmp;
     }
@@ -363,12 +399,12 @@
       if (value1 == NULL) {
         return -1;
       }
-      PyObject* value2 = PyDict_GetItem(other, key);
+      PyObject* value2 = PyDict_GetItem(other, key.get());
       if (value2 == NULL) {
         // Not found in the other dictionary
         return 0;
       }
-      int cmp = PyObject_RichCompareBool(value1, value2, Py_EQ);
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
       if (cmp != 1)  // error or not equal
           return cmp;
     }
@@ -731,6 +767,18 @@
   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 ||
@@ -889,6 +937,11 @@
   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);
 }
@@ -898,13 +951,17 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(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();
 }
@@ -918,9 +975,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)GetByCamelcaseName,
   (GetByNumberMethod)GetByNumber,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)GetItemCamelcaseName,
   (GetItemNumberMethod)GetItemNumber,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -931,6 +990,11 @@
   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);
 }
@@ -956,7 +1020,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMessageDescriptor_New(item);
+  return PyMessageDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -972,9 +1036,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1006,7 +1072,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumDescriptor_New(item);
+  return PyEnumDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1022,9 +1088,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1082,7 +1150,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumValueDescriptor_New(item);
+  return PyEnumValueDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1094,9 +1162,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)NULL,
 };
@@ -1124,7 +1194,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1140,9 +1210,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1174,7 +1246,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyOneofDescriptor_New(item);
+  return PyOneofDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1190,9 +1262,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1238,7 +1312,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumValueDescriptor_New(item);
+  return PyEnumValueDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1258,9 +1332,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)GetByNumber,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)GetItemNumber,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1302,7 +1378,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static int GetItemIndex(ItemDescriptor item) {
@@ -1314,9 +1390,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1354,7 +1432,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMessageDescriptor_New(item);
+  return PyMessageDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1370,9 +1448,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1400,7 +1480,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumDescriptor_New(item);
+  return PyEnumDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1416,9 +1496,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1446,7 +1528,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1462,9 +1544,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1488,7 +1572,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFileDescriptor_New(item);
+  return PyFileDescriptor_FromDescriptor(item);
 }
 
 static DescriptorContainerDef ContainerDef = {
@@ -1496,9 +1580,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)NULL,
 };
@@ -1522,7 +1608,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFileDescriptor_New(item);
+  return PyFileDescriptor_FromDescriptor(item);
 }
 
 static DescriptorContainerDef ContainerDef = {
@@ -1530,9 +1616,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)NULL,
 };
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
index d81537d..ce40747 100644
--- a/python/google/protobuf/pyext/descriptor_containers.h
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -28,6 +28,9 @@
 // (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.
@@ -51,6 +54,7 @@
 
 namespace message_descriptor {
 PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor);
 PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
 PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);
 
@@ -92,4 +96,6 @@
 
 }  // namespace python
 }  // namespace protobuf
+
 }  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc
new file mode 100644
index 0000000..514722b
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.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.
+
+// 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;
+  }
+  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
index bc3077b..0bc76bc 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -33,12 +33,13 @@
 #include <Python.h>
 
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/pyext/descriptor_pool.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>
 
-#define C(str) const_cast<char*>(str)
-
 #if PY_MAJOR_VERSION >= 3
   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
   #if PY_VERSION_HEX < 0x03030000
@@ -54,46 +55,118 @@
 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 {
 
-PyDescriptorPool* NewDescriptorPool() {
-  PyDescriptorPool* cdescriptor_pool = PyObject_New(
+// Create a Python DescriptorPool object, but does not fill the "pool"
+// attribute.
+static PyDescriptorPool* _CreateDescriptorPool() {
+  PyDescriptorPool* cpool = PyObject_New(
       PyDescriptorPool, &PyDescriptorPool_Type);
-  if (cdescriptor_pool == NULL) {
+  if (cpool == NULL) {
     return NULL;
   }
 
-  // Build a DescriptorPool for messages only declared in Python libraries.
-  // generated_pool() contains all messages linked in C++ libraries, and is used
-  // as underlay.
-  cdescriptor_pool->pool = new DescriptorPool(DescriptorPool::generated_pool());
+  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.
-  cdescriptor_pool->classes_by_descriptor =
+  cpool->classes_by_descriptor =
       new PyDescriptorPool::ClassesByMessageMap();
-  cdescriptor_pool->interned_descriptors =
-      new hash_map<const void*, PyObject *>();
-  cdescriptor_pool->descriptor_options =
+  cpool->descriptor_options =
       new hash_map<const void*, PyObject *>();
 
-  return cdescriptor_pool;
+  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;
-  delete self->interned_descriptors;  // its references were borrowed.
   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));
 }
 
@@ -108,30 +181,17 @@
       self->pool->FindMessageTypeByName(string(name, name_size));
 
   if (message_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find message %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
     return NULL;
   }
 
-  return PyMessageDescriptor_New(message_descriptor);
+  return PyMessageDescriptor_FromDescriptor(message_descriptor);
 }
 
 // Add a message class to our database.
-const Descriptor* RegisterMessageClass(
-    PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) {
-  ScopedPyObjectPtr full_message_name(
-      PyObject_GetAttrString(descriptor, "full_name"));
-  Py_ssize_t name_size;
-  char* name;
-  if (PyString_AsStringAndSize(full_message_name, &name, &name_size) < 0) {
-    return NULL;
-  }
-  const Descriptor *message_descriptor =
-      self->pool->FindMessageTypeByName(string(name, name_size));
-  if (!message_descriptor) {
-    PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'",
-                 name);
-    return NULL;
-  }
+int RegisterMessageClass(PyDescriptorPool* self,
+                         const Descriptor *message_descriptor,
+                         PyObject *message_class) {
   Py_INCREF(message_class);
   typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
   std::pair<iterator, bool> ret = self->classes_by_descriptor->insert(
@@ -141,7 +201,7 @@
     Py_DECREF(ret.first->second);
     ret.first->second = message_class;
   }
-  return message_descriptor;
+  return 0;
 }
 
 // Retrieve the message class added to our database.
@@ -158,6 +218,24 @@
   }
 }
 
+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;
@@ -168,12 +246,12 @@
   const FieldDescriptor* field_descriptor =
       self->pool->FindFieldByName(string(name, name_size));
   if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
+    PyErr_Format(PyExc_KeyError, "Couldn't find field %.200s",
                  name);
     return NULL;
   }
 
-  return PyFieldDescriptor_New(field_descriptor);
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
 }
 
 PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
@@ -186,11 +264,11 @@
   const FieldDescriptor* field_descriptor =
       self->pool->FindExtensionByName(string(name, name_size));
   if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find extension field %.200s", name);
     return NULL;
   }
 
-  return PyFieldDescriptor_New(field_descriptor);
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
 }
 
 PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
@@ -203,11 +281,11 @@
   const EnumDescriptor* enum_descriptor =
       self->pool->FindEnumTypeByName(string(name, name_size));
   if (enum_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find enum %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
     return NULL;
   }
 
-  return PyEnumDescriptor_New(enum_descriptor);
+  return PyEnumDescriptor_FromDescriptor(enum_descriptor);
 }
 
 PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
@@ -220,69 +298,86 @@
   const OneofDescriptor* oneof_descriptor =
       self->pool->FindOneofByName(string(name, name_size));
   if (oneof_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find oneof %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name);
     return NULL;
   }
 
-  return PyOneofDescriptor_New(oneof_descriptor);
+  return PyOneofDescriptor_FromDescriptor(oneof_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.") },
-  {NULL}
-};
+PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
 
-}  // namespace cdescriptor_pool
+  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;
+  }
 
-PyTypeObject PyDescriptorPool_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.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
-  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
-  0,                                   // tp_alloc
-  0,                                   // tp_new
-  PyObject_Del,                        // tp_free
-};
+  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.
 
@@ -301,6 +396,7 @@
     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.
@@ -311,10 +407,18 @@
   bool had_errors;
 };
 
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* serialized_pb) {
+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;
   }
@@ -327,16 +431,19 @@
 
   // 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 =
-      DescriptorPool::generated_pool()->FindFileByName(file_proto.name());
+  const FileDescriptor* generated_file = NULL;
+  if (self->underlay) {
+    generated_file = self->underlay->FindFileByName(file_proto.name());
+  }
   if (generated_file != NULL) {
-    return PyFileDescriptor_NewWithPb(generated_file, serialized_pb);
+    return PyFileDescriptor_FromDescriptorWithSerializedPb(
+        generated_file, serialized_pb);
   }
 
   BuildFileErrorCollector error_collector;
   const FileDescriptor* descriptor =
-      GetDescriptorPool()->pool->BuildFileCollectingErrors(file_proto,
-                                                           &error_collector);
+      self->pool->BuildFileCollectingErrors(file_proto,
+                                            &error_collector);
   if (descriptor == NULL) {
     PyErr_Format(PyExc_TypeError,
                  "Couldn't build proto file into descriptor pool!\n%s",
@@ -344,25 +451,141 @@
     return NULL;
   }
 
-  return PyFileDescriptor_NewWithPb(descriptor, serialized_pb);
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(
+      descriptor, serialized_pb);
 }
 
-static PyDescriptorPool* global_cdescriptor_pool = NULL;
+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;
 
-  global_cdescriptor_pool = cdescriptor_pool::NewDescriptorPool();
-  if (global_cdescriptor_pool == NULL) {
+  // 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;
 }
 
-PyDescriptorPool* GetDescriptorPool() {
-  return global_cdescriptor_pool;
+// 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
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
index 4e494b8..16bc910 100644
--- a/python/google/protobuf/pyext/descriptor_pool.h
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -38,6 +38,8 @@
 
 namespace google {
 namespace protobuf {
+class MessageFactory;
+
 namespace python {
 
 // Wraps operations to the global DescriptorPool which contains information
@@ -53,8 +55,25 @@
 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.
@@ -62,14 +81,6 @@
   typedef hash_map<const Descriptor*, PyObject*> ClassesByMessageMap;
   ClassesByMessageMap* classes_by_descriptor;
 
-  // 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;
-
   // Cache the options for any kind of descriptor.
   // Descriptor pointers are owned by the DescriptorPool above.
   // Python objects are owned by the map.
@@ -81,19 +92,16 @@
 
 namespace cdescriptor_pool {
 
-// Builds a new DescriptorPool. Normally called only once per process.
-PyDescriptorPool* NewDescriptorPool();
-
 // 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.
-// Returns the message Descriptor.
-// On error, returns NULL with a Python exception set.
-const Descriptor* RegisterMessageClass(
-    PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor);
+// On error, returns -1 with a Python exception set.
+int RegisterMessageClass(PyDescriptorPool* self,
+                         const Descriptor* message_descriptor,
+                         PyObject* message_class);
 
 // Retrieves the Python class registered with the given message descriptor.
 //
@@ -102,6 +110,8 @@
 PyObject* 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.
 //
@@ -134,13 +144,15 @@
 
 }  // namespace cdescriptor_pool
 
-// Implement the Python "_BuildFile" method, it takes a serialized
-// FileDescriptorProto, and adds it to the C++ DescriptorPool.
-// It returns a new FileDescriptor object, or NULL when an exception is raised.
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* args);
-
 // Retrieve the global descriptor pool owned by the _message module.
-PyDescriptorPool* GetDescriptorPool();
+// 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();
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index 8e38fc4..555bd29 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -33,6 +33,7 @@
 
 #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>
@@ -51,16 +52,6 @@
 
 namespace extension_dict {
 
-// TODO(tibell): Always use self->message for clarity, just like in
-// RepeatedCompositeContainer.
-static Message* GetMessage(ExtensionDict* self) {
-  if (self->parent != NULL) {
-    return self->parent->message;
-  } else {
-    return self->message;
-  }
-}
-
 PyObject* len(ExtensionDict* self) {
 #if PY_MAJOR_VERSION >= 3
   return PyLong_FromLong(PyDict_Size(self->values));
@@ -89,7 +80,7 @@
     }
   } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     if (cmessage::ReleaseSubMessage(
-            GetMessage(self), descriptor,
+            self->parent, descriptor,
             reinterpret_cast<CMessage*>(extension)) < 0) {
       return -1;
     }
@@ -103,13 +94,13 @@
   if (descriptor == NULL) {
     return NULL;
   }
-  if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+  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);
@@ -118,6 +109,14 @@
     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(
@@ -132,7 +131,8 @@
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       PyObject *message_class = cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), descriptor->message_type());
+          cmessage::GetDescriptorPoolForMessage(self->parent),
+          descriptor->message_type());
       if (message_class == NULL) {
         return NULL;
       }
@@ -162,7 +162,7 @@
   if (descriptor == NULL) {
     return -1;
   }
-  if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+  if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
     return -1;
   }
 
@@ -172,9 +172,11 @@
                     "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);
@@ -188,14 +190,17 @@
     return NULL;
   }
   PyObject* value = PyDict_GetItem(self->values, extension);
-  if (value != NULL) {
-    if (ReleaseExtension(self, value, 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, descriptor) == NULL) {
-    return NULL;
-  }
   if (PyDict_DelItem(self->values, extension) < 0) {
     PyErr_Clear();
   }
@@ -208,8 +213,15 @@
   if (descriptor == NULL) {
     return NULL;
   }
-  PyObject* result = cmessage::HasFieldByDescriptor(self->parent, 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) {
@@ -218,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 {
@@ -266,8 +278,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
@@ -279,7 +290,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
diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h
index 7e1049f..d92cf95 100644
--- a/python/google/protobuf/pyext/extension_dict.h
+++ b/python/google/protobuf/pyext/extension_dict.h
@@ -47,7 +47,11 @@
 class Message;
 class FieldDescriptor;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
@@ -113,11 +117,6 @@
 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.
 //
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
new file mode 100644
index 0000000..df9138a
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -0,0 +1,965 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <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;
+
+  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->subclass_init,
+                                               message->GetDescriptor());
+    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,
+    PyObject* concrete_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(concrete_class);
+  self->subclass_init = concrete_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_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..ddf94be
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.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.
+
+#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;
+
+// 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 {
+  // A callable that is used to create new child messages.
+  PyObject* subclass_init;
+
+  // 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,
+    PyObject* concrete_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 a2b357b..863cde0 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -33,6 +33,7 @@
 
 #include <google/protobuf/pyext/message.h>
 
+#include <map>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
@@ -49,16 +50,19 @@
 #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>
 
@@ -86,16 +90,357 @@
 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;
+
+// Defines the Metaclass of all Message 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 PyMessageMeta {
+  // 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;
+};
+
+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>).
+  //
+  // The enum descriptor we get from
+  // <messagedescriptor>.enum_types_by_name[name]
+  // which was built previously.
+  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;
+  }
+  PyMessageMeta* newtype = reinterpret_cast<PyMessageMeta*>(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, result.get()) < 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(PyMessageMeta *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 PyMessageMeta_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MessageMeta",     // tp_name
+  sizeof(PyMessageMeta),               // 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 PyMessageMeta* CheckMessageClass(PyTypeObject* cls) {
+  if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) {
+    PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
+    return NULL;
+  }
+  return reinterpret_cast<PyMessageMeta*>(cls);
+}
+
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+  PyMessageMeta* type = CheckMessageClass(cls);
+  if (type == NULL) {
+    return NULL;
+  }
+  return type->message_descriptor;
+}
+
 // Forward declarations
 namespace cmessage {
-static const FieldDescriptor* GetFieldDescriptor(
-    CMessage* self, PyObject* name);
-static const Descriptor* GetMessageDescriptor(PyTypeObject* cls);
-static string GetMessageName(CMessage* self);
 int InternalReleaseFieldByDescriptor(
+    CMessage* self,
     const FieldDescriptor* field_descriptor,
-    PyObject* composite_field,
-    Message* parent_message);
+    PyObject* composite_field);
 }  // namespace cmessage
 
 // ---------------------------------------------------------------------
@@ -127,10 +472,17 @@
                                Visitor visitor) {
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      RepeatedCompositeContainer* container =
-        reinterpret_cast<RepeatedCompositeContainer*>(child);
-      if (visitor.VisitRepeatedCompositeContainer(container) == -1)
-        return -1;
+      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);
@@ -159,7 +511,7 @@
   if (self->composite_fields) {
     // Never use self->message in this function, it may be already freed.
     const Descriptor* message_descriptor =
-        cmessage::GetMessageDescriptor(Py_TYPE(self));
+        GetMessageDescriptor(Py_TYPE(self));
     while (PyDict_Next(self->composite_fields, &pos, &key, &field)) {
       Py_ssize_t key_str_size;
       char *key_str_data;
@@ -192,8 +544,6 @@
 
 // ---------------------------------------------------------------------
 
-static DynamicMessageFactory* message_factory;
-
 // Constants used for integer type range checking.
 PyObject* kPythonZero;
 PyObject* kint32min_py;
@@ -203,17 +553,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_cdescriptor;
 static PyObject* kfull_name;
-static PyObject* k_extensions_by_name;
-static PyObject* k_extensions_by_number;
 
 /* Is 64bit */
 void FormatTypeError(PyObject* arg, char* expected_types) {
@@ -246,12 +592,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;
   }
@@ -309,38 +657,51 @@
   return true;
 }
 
-bool CheckAndSetString(
-    PyObject* arg, Message* message,
-    const FieldDescriptor* descriptor,
-    const Reflection* reflection,
-    bool append,
-    int index) {
+// 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;
+  }
+}
+
+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 false;
+      return NULL;
     }
 
-    if (PyBytes_Check(arg)) {
-      PyObject* unicode = PyUnicode_FromEncodedObject(arg, "utf-8", NULL);
-      if (unicode == NULL) {
-        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 false;
-      } else {
-        Py_DECREF(unicode);
-      }
+    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;
@@ -358,14 +719,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;
   }
 
@@ -377,7 +748,6 @@
   } else {
     reflection->SetRepeatedString(message, descriptor, index, value_string);
   }
-  Py_DECREF(encoded_string);
   return true;
 }
 
@@ -411,8 +781,15 @@
 
 namespace cmessage {
 
-DynamicMessageFactory* GetMessageFactory() {
-  return message_factory;
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) {
+  // No need to check the type: the type of instances of CMessage is always
+  // an instance of PyMessageMeta. Let's prove it with a debug-only check.
+  GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type));
+  return reinterpret_cast<PyMessageMeta*>(Py_TYPE(message))->py_descriptor_pool;
+}
+
+MessageFactory* GetFactoryForMessage(CMessage* message) {
+  return GetDescriptorPoolForMessage(message)->message_factory;
 }
 
 static int MaybeReleaseOverlappingOneofField(
@@ -444,7 +821,7 @@
   }
 
   if (InternalReleaseFieldByDescriptor(
-          existing_field, child_message, message) < 0) {
+          cmessage, existing_field, child_message) < 0) {
     return -1;
   }
   return PyDict_DelItemString(cmessage->composite_fields, field_name);
@@ -465,7 +842,7 @@
     return NULL;
   }
   return reflection->MutableMessage(
-      parent_message, parent_field, message_factory);
+      parent_message, parent_field, GetFactoryForMessage(parent));
 }
 
 struct FixupMessageReference : public ChildVisitor {
@@ -483,6 +860,11 @@
     return 0;
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    container->message = message_;
+    return 0;
+  }
+
  private:
   Message* message_;
 };
@@ -496,17 +878,17 @@
     // 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 = 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.
-    Message* parent_message = self->parent->message;
     Message* mutable_message = GetMutableMessage(
         self->parent,
         self->parent_field_descriptor);
@@ -520,8 +902,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)
@@ -532,23 +914,6 @@
 
 // --- Globals:
 
-// Retrieve the C++ Descriptor of a message class.
-// On error, returns NULL with an exception set.
-static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
-  ScopedPyObjectPtr descriptor(PyObject_GetAttr(
-      reinterpret_cast<PyObject*>(cls), kDESCRIPTOR));
-  if (descriptor == NULL) {
-    PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
-    return NULL;
-  }
-  if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) {
-    PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
-                 descriptor->ob_type->tp_name);
-    return NULL;
-  }
-  return PyMessageDescriptor_AsDescriptor(descriptor);
-}
-
 // Retrieve a C++ FieldDescriptor for a message attribute.
 // The C++ message must be valid.
 // TODO(amauryfa): This function should stay internal, because exception
@@ -583,15 +948,43 @@
   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
 // container CMessages instead of just removing. Repeated composite container
 // 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(
-    Message* message,
+    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 Reflection* reflection = message->GetReflection();
   int min, max;
@@ -665,7 +1058,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;
       }
@@ -692,26 +1085,102 @@
     }
     const FieldDescriptor* descriptor = GetFieldDescriptor(self, name);
     if (descriptor == NULL) {
-      PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.",
+      PyErr_Format(PyExc_ValueError, "Protocol message %s has no \"%s\" field.",
+                   self->message->GetDescriptor()->name().c_str(),
                    PyString_AsString(name));
       return -1;
     }
-    if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    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() == FieldDescriptor::CPPTYPE_MESSAGE) {
-        if (repeated_composite_container::Extend(
-                reinterpret_cast<RepeatedCompositeContainer*>(container.get()),
-                value)
-            == NULL) {
+        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;
         }
@@ -721,12 +1190,27 @@
       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;
       }
     }
@@ -751,32 +1235,24 @@
 
   self->composite_fields = NULL;
 
-  // If there are extension_ranges, the message is "extendable". Allocate a
-  // dictionary to store the extension fields.
-  if (descriptor->extension_range_count() > 0) {
-    // TODO(amauryfa): Delay the construction of this dict until extensions are
-    // really used on the object.
-    ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
-    if (extension_dict == NULL) {
-      return NULL;
-    }
-    self->extensions = extension_dict;
-  }
-
   return self;
 }
 
 // The __new__ method of Message classes.
 // Creates a new C++ message and takes ownership.
-static PyObject* New(PyTypeObject* type,
+static PyObject* New(PyTypeObject* cls,
                      PyObject* unused_args, PyObject* unused_kwargs) {
+  PyMessageMeta* type = CheckMessageClass(cls);
+  if (type == NULL) {
+    return NULL;
+  }
   // Retrieve the message descriptor and the default instance (=prototype).
-  const Descriptor* message_descriptor = GetMessageDescriptor(type);
+  const Descriptor* message_descriptor = type->message_descriptor;
   if (message_descriptor == NULL) {
     return NULL;
   }
-  const Message* default_message =
-      message_factory->GetPrototype(message_descriptor);
+  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;
@@ -789,7 +1265,6 @@
   }
   self->message = default_message->New();
   self->owner.reset(self->message);
-
   return reinterpret_cast<PyObject*>(self);
 }
 
@@ -830,6 +1305,11 @@
     return 0;
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    container->parent = NULL;
+    return 0;
+  }
+
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
     cmessage->parent = NULL;
@@ -840,6 +1320,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);
@@ -1001,20 +1484,27 @@
   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);
 }
 
 // ---------------------------------------------------------------------
@@ -1064,6 +1554,11 @@
     return 0;
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    container->SetOwner(new_owner_);
+    return 0;
+  }
+
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
     return SetOwner(cmessage, new_owner_);
@@ -1084,11 +1579,12 @@
 // 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(Message* message,
+Message* ReleaseMessage(CMessage* self,
                         const Descriptor* descriptor,
                         const FieldDescriptor* field_descriptor) {
-  Message* released_message = message->GetReflection()->ReleaseMessage(
-      message, field_descriptor, message_factory);
+  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
@@ -1102,12 +1598,12 @@
   return released_message;
 }
 
-int ReleaseSubMessage(Message* message,
+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;
@@ -1119,8 +1615,8 @@
 
 struct ReleaseChild : public ChildVisitor {
   // message must outlive this object.
-  explicit ReleaseChild(Message* parent_message) :
-      parent_message_(parent_message) {}
+  explicit ReleaseChild(CMessage* parent) :
+      parent_(parent) {}
 
   int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
     return repeated_composite_container::Release(
@@ -1132,23 +1628,27 @@
         reinterpret_cast<RepeatedScalarContainer*>(container));
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    return reinterpret_cast<MapContainer*>(container)->Release();
+  }
+
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
-    return ReleaseSubMessage(parent_message_, field_descriptor,
+    return ReleaseSubMessage(parent_, field_descriptor,
         reinterpret_cast<CMessage*>(cmessage));
   }
 
-  Message* parent_message_;
+  CMessage* parent_;
 };
 
 int InternalReleaseFieldByDescriptor(
+    CMessage* self,
     const FieldDescriptor* field_descriptor,
-    PyObject* composite_field,
-    Message* parent_message) {
+    PyObject* composite_field) {
   return VisitCompositeField(
       field_descriptor,
       composite_field,
-      ReleaseChild(parent_message));
+      ReleaseChild(self));
 }
 
 PyObject* ClearFieldByDescriptor(
@@ -1200,8 +1700,8 @@
   // Only release the field if there's a possibility that there are
   // references to it.
   if (composite_field != NULL) {
-    if (InternalReleaseFieldByDescriptor(field_descriptor,
-                                         composite_field, message) < 0) {
+    if (InternalReleaseFieldByDescriptor(self, field_descriptor,
+                                         composite_field) < 0) {
       return NULL;
     }
     PyDict_DelItem(self->composite_fields, arg);
@@ -1219,19 +1719,9 @@
 
 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);
-    ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
-    if (extension_dict == NULL) {
-      return NULL;
-    }
-    self->extensions = extension_dict;
-  }
+  Py_CLEAR(self->extensions);
   if (self->composite_fields) {
     PyDict_Clear(self->composite_fields);
   }
@@ -1279,13 +1769,13 @@
     }
 
     ScopedPyObjectPtr encode_error(
-        PyObject_GetAttrString(message_module, "EncodeError"));
+        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));
+                 GetMessageName(self).c_str(), PyString_AsString(joined.get()));
     return NULL;
   }
   int size = self->message->ByteSize();
@@ -1312,34 +1802,38 @@
 // appropriate.
 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) {
@@ -1410,7 +1904,7 @@
 
   // 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);
 
@@ -1427,7 +1921,8 @@
   AssureWritable(self);
   io::CodedInputStream input(
       reinterpret_cast<const uint8*>(data), data_length);
-  input.SetExtensionRegistry(GetDescriptorPool()->pool, message_factory);
+  PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
+  input.SetExtensionRegistry(pool->pool, pool->message_factory);
   bool success = self->message->MergePartialFromCodedStream(&input);
   if (success) {
     return PyInt_FromLong(input.CurrentPosition());
@@ -1438,7 +1933,7 @@
 }
 
 static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
-  if (Clear(self) == NULL) {
+  if (ScopedPyObjectPtr(Clear(self)) == NULL) {
     return NULL;
   }
   return MergeFromString(self, arg);
@@ -1450,25 +1945,11 @@
 
 static PyObject* RegisterExtension(PyObject* cls,
                                    PyObject* extension_handle) {
-  ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR));
-  if (message_descriptor == NULL) {
-    return NULL;
-  }
-
   const FieldDescriptor* descriptor =
       GetExtensionDescriptor(extension_handle);
   if (descriptor == NULL) {
     return NULL;
   }
-  const Descriptor* cmessage_descriptor = GetMessageDescriptor(
-      reinterpret_cast<PyTypeObject*>(cls));
-
-  if (cmessage_descriptor != descriptor->containing_type()) {
-    if (PyObject_SetAttrString(extension_handle, "containing_type",
-                               message_descriptor) < 0) {
-      return NULL;
-    }
-  }
 
   ScopedPyObjectPtr extensions_by_name(
       PyObject_GetAttr(cls, k_extensions_by_name));
@@ -1482,7 +1963,8 @@
   }
 
   // If the extension was already registered, check that it is the same.
-  PyObject* existing_extension = PyDict_GetItem(extensions_by_name, full_name);
+  PyObject* existing_extension =
+      PyDict_GetItem(extensions_by_name.get(), full_name.get());
   if (existing_extension != NULL) {
     const FieldDescriptor* existing_extension_descriptor =
         GetExtensionDescriptor(existing_extension);
@@ -1494,7 +1976,8 @@
     Py_RETURN_NONE;
   }
 
-  if (PyDict_SetItem(extensions_by_name, full_name, extension_handle) < 0) {
+  if (PyDict_SetItem(extensions_by_name.get(), full_name.get(),
+                     extension_handle) < 0) {
     return NULL;
   }
 
@@ -1509,7 +1992,8 @@
   if (number == NULL) {
     return NULL;
   }
-  if (PyDict_SetItem(extensions_by_number, number, extension_handle) < 0) {
+  if (PyDict_SetItem(extensions_by_number.get(), number.get(),
+                     extension_handle) < 0) {
     return NULL;
   }
 
@@ -1517,7 +2001,6 @@
   if (descriptor->is_extension() &&
       descriptor->containing_type()->options().message_set_wire_format() &&
       descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
-      descriptor->message_type() == descriptor->extension_scope() &&
       descriptor->label() == FieldDescriptor::LABEL_OPTIONAL) {
     ScopedPyObjectPtr message_name(PyString_FromStringAndSize(
         descriptor->message_type()->full_name().c_str(),
@@ -1525,7 +2008,8 @@
     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;
@@ -1561,6 +2045,8 @@
   }
 }
 
+static PyObject* GetExtensionDict(CMessage* self, void *closure);
+
 static PyObject* ListFields(CMessage* self) {
   vector<const FieldDescriptor*> fields;
   self->message->GetReflection()->ListFields(*self->message, &fields);
@@ -1575,14 +2061,15 @@
   // 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) {
       return NULL;
     }
 
     if (fields[i]->is_extension()) {
-      ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(fields[i]));
+      ScopedPyObjectPtr extension_field(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
       if (extension_field == NULL) {
         return NULL;
       }
@@ -1592,16 +2079,18 @@
       // TODO(amauryfa): consider building the class on the fly!
       if (fields[i]->message_type() != NULL &&
           cdescriptor_pool::GetMessageClass(
-              GetDescriptorPool(), fields[i]->message_type()) == NULL) {
+              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) {
         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) {
         return NULL;
       }
@@ -1609,6 +2098,7 @@
       // 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()));
@@ -1616,14 +2106,15 @@
         PyErr_SetString(PyExc_ValueError, "bad string");
         return NULL;
       }
-      ScopedPyObjectPtr field_descriptor(PyFieldDescriptor_New(fields[i]));
+      ScopedPyObjectPtr field_descriptor(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
       if (field_descriptor == NULL) {
         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);
+        PyErr_SetObject(PyExc_ValueError, py_field_name.get());
         return NULL;
       }
       PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release());
@@ -1645,7 +2136,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());
@@ -1659,34 +2150,38 @@
 }
 
 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));
-    if (!self_fields) {
-      return NULL;
-    }
-    ScopedPyObjectPtr other_fields(ListFields(
-        reinterpret_cast<CMessage*>(other)));
-    if (!other_fields) {
-      return NULL;
-    }
-    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 FieldDescriptor* field_descriptor) {
-  Message* message = self->message;
+PyObject* InternalGetScalar(const Message* message,
+                            const FieldDescriptor* field_descriptor) {
   const Reflection* reflection = message->GetReflection();
 
   if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
@@ -1739,12 +2234,14 @@
       if (!message->GetReflection()->SupportsUnknownEnumValues() &&
           !message->GetReflection()->HasField(*message, field_descriptor)) {
         // Look for the value in the unknown fields.
-        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;
           }
         }
@@ -1769,11 +2266,12 @@
 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, message_factory);
+      *self->message, field_descriptor, pool->message_factory);
 
   PyObject *message_class = cdescriptor_pool::GetMessageClass(
-      GetDescriptorPool(), field_descriptor->message_type());
+      pool, field_descriptor->message_type());
   if (message_class == NULL) {
     return NULL;
   }
@@ -1793,21 +2291,16 @@
   return reinterpret_cast<PyObject*>(cmsg);
 }
 
-int InternalSetScalar(
-    CMessage* self,
+int InternalSetNonOneofScalar(
+    Message* message,
     const FieldDescriptor* field_descriptor,
     PyObject* arg) {
-  Message* message = self->message;
   const Reflection* reflection = message->GetReflection();
 
   if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
     return -1;
   }
 
-  if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) {
-    return -1;
-  }
-
   switch (field_descriptor->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32: {
       GOOGLE_CHECK_GET_INT32(arg, value, -1);
@@ -1878,6 +2371,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);
@@ -1895,124 +2403,6 @@
   return py_cmsg;
 }
 
-// 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, number) == -1) {
-    return false;
-  }
-  return true;
-}
-
-
-// Finalize the creation of the Message class.
-// Called from its metaclass: GeneratedProtocolMessageType.__init__().
-static PyObject* AddDescriptors(PyObject* cls, PyObject* descriptor) {
-  const Descriptor* message_descriptor =
-      cdescriptor_pool::RegisterMessageClass(
-          GetDescriptorPool(), cls, descriptor);
-  if (message_descriptor == NULL) {
-    return NULL;
-  }
-
-  // If there are extension_ranges, the message is "extendable", and extension
-  // classes will register themselves in this class.
-  if (message_descriptor->extension_range_count() > 0) {
-    ScopedPyObjectPtr by_name(PyDict_New());
-    if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) {
-      return NULL;
-    }
-    ScopedPyObjectPtr by_number(PyDict_New());
-    if (PyObject_SetAttr(cls, k_extensions_by_number, by_number) < 0) {
-      return NULL;
-    }
-  }
-
-  // For each field set: cls.<field>_FIELD_NUMBER = <number>
-  for (int i = 0; i < message_descriptor->field_count(); ++i) {
-    if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) {
-      return NULL;
-    }
-  }
-
-  // For each enum set cls.<enum name> = EnumTypeWrapper(<enum descriptor>).
-  //
-  // The enum descriptor we get from
-  // <messagedescriptor>.enum_types_by_name[name]
-  // which was built previously.
-  for (int i = 0; i < message_descriptor->enum_type_count(); ++i) {
-    const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i);
-    ScopedPyObjectPtr enum_type(PyEnumDescriptor_New(enum_descriptor));
-    if (enum_type == NULL) {
-      return NULL;
-     }
-    // Add wrapped enum type to message class.
-    ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
-        EnumTypeWrapper_class, enum_type.get(), NULL));
-    if (wrapped == NULL) {
-      return NULL;
-    }
-    if (PyObject_SetAttrString(
-            cls, enum_descriptor->name().c_str(), wrapped) == -1) {
-      return NULL;
-    }
-
-    // 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 NULL;
-      }
-      if (PyObject_SetAttrString(
-              cls, enum_value_descriptor->name().c_str(), value_number) == -1) {
-        return NULL;
-      }
-    }
-  }
-
-  // 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 < message_descriptor->extension_count(); ++i) {
-    const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i);
-    ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(field));
-    if (extension_field == NULL) {
-      return NULL;
-    }
-
-    // Add the extension field to the message class.
-    if (PyObject_SetAttrString(
-            cls, field->name().c_str(), extension_field) == -1) {
-      return NULL;
-    }
-
-    // For each extension set cls.<extension name>_FIELD_NUMBER = <number>.
-    if (!AddFieldNumberToClass(cls, field)) {
-      return NULL;
-    }
-  }
-
-  Py_RETURN_NONE;
-}
-
 PyObject* DeepCopy(CMessage* self, PyObject* arg) {
   PyObject* clone = PyObject_CallObject(
       reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL);
@@ -2023,8 +2413,9 @@
     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;
   }
@@ -2043,16 +2434,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;
@@ -2075,7 +2466,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());
@@ -2090,33 +2481,13 @@
   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* _GetMessageDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindMessageByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetFieldDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindFieldByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetExtensionDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindExtensionByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetEnumDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindEnumTypeByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetOneofDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindOneofByName(GetDescriptorPool(), arg);
-}
-
 PyObject* _CheckCalledFromGeneratedFile(PyObject* unused,
                                         PyObject* unused_arg) {
   if (!_CalledFromGeneratedFile(1)) {
@@ -2128,9 +2499,31 @@
   Py_RETURN_NONE;
 }
 
-static PyMemberDef Members[] = {
-  {"Extensions", T_OBJECT_EX, offsetof(CMessage, extensions), 0,
-   "Extension dict"},
+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 PyGetSetDef Getters[] = {
+  {"Extensions", (getter)GetExtensionDict, NULL, "Extension dict"},
   {NULL}
 };
 
@@ -2143,8 +2536,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,
@@ -2188,21 +2579,6 @@
     "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." },
-  { "_GetMessageDescriptor", (PyCFunction)_GetMessageDescriptor,
-    METH_O | METH_STATIC, "Finds a message descriptor in the message 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." },
-  { "_GetEnumDescriptor", (PyCFunction)_GetEnumDescriptor,
-    METH_O | METH_STATIC,
-    "Finds an enum descriptor in the message pool." },
-  { "_GetOneofDescriptor", (PyCFunction)_GetOneofDescriptor,
-    METH_O | METH_STATIC,
-    "Finds an oneof descriptor in the message pool." },
   { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile,
     METH_NOARGS | METH_STATIC,
     "Raises TypeError if the caller is not in a _pb2.py file."},
@@ -2234,11 +2610,36 @@
         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) {
+      PyObject* 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) {
       PyObject *message_class = cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), field_descriptor->message_type());
+          GetDescriptorPoolForMessage(self), field_descriptor->message_type());
       if (message_class == NULL) {
         return NULL;
       }
@@ -2260,6 +2661,9 @@
 
   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;
@@ -2267,7 +2671,7 @@
     return sub_message;
   }
 
-  return InternalGetScalar(self, field_descriptor);
+  return InternalGetScalar(self->message, field_descriptor);
 }
 
 int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
@@ -2296,17 +2700,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)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.pyext._message."
-  "CMessage",                          // tp_name
+  PyVarObject_HEAD_INIT(&PyMessageMeta_Type, 0)
+  FULL_MODULE_NAME ".CMessage",        // tp_name
   sizeof(CMessage),                    // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)cmessage::Dealloc,       //  tp_dealloc
@@ -2318,7 +2723,7 @@
   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
@@ -2333,8 +2738,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
@@ -2401,8 +2806,9 @@
   k_extensions_by_name = PyString_FromString("_extensions_by_name");
   k_extensions_by_number = PyString_FromString("_extensions_by_number");
 
-  message_factory = new DynamicMessageFactory(GetDescriptorPool()->pool);
-  message_factory->SetDelegateToGeneratedFactory(true);
+  PyObject *dummy_obj = PySet_New(NULL);
+  kEmptyWeakref = PyWeakref_NewRef(dummy_obj, NULL);
+  Py_DECREF(dummy_obj);
 }
 
 bool InitProto2MessageModule(PyObject *m) {
@@ -2419,7 +2825,13 @@
   // Initialize constants defined in this file.
   InitGlobals();
 
-  CMessage_Type.tp_hash = PyObject_HashNotImplemented;
+  PyMessageMeta_Type.tp_base = &PyType_Type;
+  if (PyType_Ready(&PyMessageMeta_Type) < 0) {
+    return false;
+  }
+  PyModule_AddObject(m, "MessageMeta",
+                     reinterpret_cast<PyObject*>(&PyMessageMeta_Type));
+
   if (PyType_Ready(&CMessage_Type) < 0) {
     return false;
   }
@@ -2434,50 +2846,144 @@
   if (empty_dict == NULL) {
     return false;
   }
-  ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict));
+  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) < 0) {
+                     k_extensions_by_name, immutable_dict.get()) < 0) {
     return false;
   }
   if (PyDict_SetItem(CMessage_Type.tp_dict,
-                     k_extensions_by_number, immutable_dict) < 0) {
+                     k_extensions_by_number, immutable_dict.get()) < 0) {
     return false;
   }
 
   PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&CMessage_Type));
 
-  RepeatedScalarContainer_Type.tp_hash =
-      PyObject_HashNotImplemented;
-  if (PyType_Ready(&RepeatedScalarContainer_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, "RepeatedScalarContainer",
-                     reinterpret_cast<PyObject*>(
-                         &RepeatedScalarContainer_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;
+    }
 
-  RepeatedCompositeContainer_Type.tp_hash = PyObject_HashNotImplemented;
-  if (PyType_Ready(&RepeatedCompositeContainer_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
   }
 
-  PyModule_AddObject(
-      m, "RepeatedCompositeContainer",
-      reinterpret_cast<PyObject*>(
-          &RepeatedCompositeContainer_Type));
-
-  ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented;
   if (PyType_Ready(&ExtensionDict_Type) < 0) {
     return false;
   }
-
   PyModule_AddObject(
       m, "ExtensionDict",
       reinterpret_cast<PyObject*>(&ExtensionDict_Type));
 
+  // 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);
@@ -2511,6 +3017,7 @@
   }
   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");
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 2f2da79..cc0012e 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -49,13 +49,20 @@
 class Reflection;
 class FieldDescriptor;
 class Descriptor;
-class DynamicMessageFactory;
+class DescriptorPool;
+class MessageFactory;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+using std::string;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
 struct ExtensionDict;
+struct PyDescriptorPool;
 
 typedef struct CMessage {
   PyObject_HEAD;
@@ -120,7 +127,7 @@
 // A new message will be created if this is a read-only default instance.
 //
 // Corresponds to reflection api method ReleaseMessage.
-int ReleaseSubMessage(Message* message,
+int ReleaseSubMessage(CMessage* self,
                       const FieldDescriptor* field_descriptor,
                       CMessage* child_cmessage);
 
@@ -144,7 +151,7 @@
 // by slice will be removed from cmessage_list by this function.
 //
 // Corresponds to reflection api method RemoveLast.
-int InternalDeleteRepeatedField(Message* message,
+int InternalDeleteRepeatedField(CMessage* self,
                                 const FieldDescriptor* field_descriptor,
                                 PyObject* slice, PyObject* cmessage_list);
 
@@ -153,10 +160,15 @@
                       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,
+PyObject* InternalGetScalar(const Message* message,
                             const FieldDescriptor* field_descriptor);
 
 // Clears the message, removing all contained data. Extension dictionary and
@@ -217,7 +229,14 @@
 
 int AssureWritable(CMessage* self);
 
-DynamicMessageFactory* GetMessageFactory();
+// 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
 
@@ -279,7 +298,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>
@@ -288,6 +307,7 @@
 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, Message* message,
     const FieldDescriptor* descriptor,
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index 0fe98e7..b01123b 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>
 
@@ -74,125 +76,6 @@
     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);
-
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-  const 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()
 
@@ -233,7 +116,7 @@
     cmsg->owner = self->owner;
     cmsg->message = const_cast<Message*>(&sub_message);
     cmsg->parent = self->parent;
-    if (PyList_Append(self->child_messages, py_cmsg) < 0) {
+    if (PyList_Append(self->child_messages, py_cmsg.get()) < 0) {
       return -1;
     }
   }
@@ -319,8 +202,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;
     }
@@ -329,7 +212,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;
     }
   }
@@ -367,8 +251,8 @@
   }
 
   // Delete from the underlying Message, if any.
-  if (self->message != NULL) {
-    if (cmessage::InternalDeleteRepeatedField(self->message,
+  if (self->parent != NULL) {
+    if (cmessage::InternalDeleteRepeatedField(self->parent,
                                               self->parent_field_descriptor,
                                               slice,
                                               self->child_messages) < 0) {
@@ -411,7 +295,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;
@@ -435,17 +319,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;
@@ -455,58 +339,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) {
-    Message* message = self->message;
-    const Reflection* reflection = message->GetReflection();
-    const 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,
@@ -527,11 +392,10 @@
   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;
 }
 
 // ---------------------------------------------------------------------
@@ -566,53 +430,29 @@
     return NULL;
   }
   ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index));
-  if (AssignSubscript(self, py_index, NULL) < 0) {
+  if (AssignSubscript(self, py_index.get(), NULL) < 0) {
     return NULL;
   }
   return item;
 }
 
-// The caller takes ownership of the returned Message.
-Message* ReleaseLast(const FieldDescriptor* field,
-                     const Descriptor* type,
-                     Message* message) {
+// 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(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 =
-        cmessage::GetMessageFactory()->GetPrototype(type);
-    GOOGLE_CHECK_NOTNULL(prototype);
-    return prototype->New();
-  } else {
-    return released_message;
-  }
-}
-
-// Release field of message and transfer the ownership to cmessage.
-void ReleaseLastTo(const FieldDescriptor* field,
-                   Message* message,
-                   CMessage* cmessage) {
-  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_descriptor = 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
@@ -635,7 +475,7 @@
   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.
@@ -732,9 +572,7 @@
 
 PyTypeObject RepeatedCompositeContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.pyext._message."
-  "RepeatedCompositeContainer",        // tp_name
+  FULL_MODULE_NAME ".RepeatedCompositeContainer",  // tp_name
   sizeof(RepeatedCompositeContainer),  // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)repeated_composite_container::Dealloc,  //  tp_dealloc
@@ -746,7 +584,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
diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h
index ce7cee0..58d37b0 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.h
+++ b/python/google/protobuf/pyext/repeated_composite_container.h
@@ -49,7 +49,11 @@
 class FieldDescriptor;
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
@@ -108,9 +112,6 @@
     const FieldDescriptor* parent_field_descriptor,
     PyObject *concrete_class);
 
-// Returns the number of items in this repeated composite container.
-static Py_ssize_t Length(RepeatedCompositeContainer* self);
-
 // Appends a new CMessage to the container and returns it.  The
 // CMessage is initialized using the content of kwargs.
 //
@@ -161,13 +162,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 110a4c8..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>
 
@@ -68,7 +70,7 @@
                                              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;
     }
   }
@@ -102,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))) {
@@ -170,7 +172,7 @@
           ScopedPyObjectPtr s(PyObject_Str(arg));
           if (s != NULL) {
             PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                         PyString_AsString(s));
+                         PyString_AsString(s.get()));
           }
           return -1;
         }
@@ -332,7 +334,7 @@
         break;
       }
       ScopedPyObjectPtr s(Item(self, index));
-      PyList_Append(list, s);
+      PyList_Append(list, s.get());
     }
   } else {
     if (step > 0) {
@@ -343,7 +345,7 @@
         break;
       }
       ScopedPyObjectPtr s(Item(self, index));
-      PyList_Append(list, s);
+      PyList_Append(list, s.get());
     }
   }
   return list;
@@ -412,7 +414,7 @@
           ScopedPyObjectPtr s(PyObject_Str(item));
           if (s != NULL) {
             PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                         PyString_AsString(s));
+                         PyString_AsString(s.get()));
           }
           return NULL;
         }
@@ -470,7 +472,7 @@
 
   if (value == NULL) {
     return cmessage::InternalDeleteRepeatedField(
-        message, field_descriptor, slice, NULL);
+        self->parent, field_descriptor, slice, NULL);
   }
 
   if (!create_list) {
@@ -481,15 +483,15 @@
   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) {
@@ -509,8 +511,8 @@
     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;
     }
   }
@@ -527,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;
   }
@@ -542,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;
     }
@@ -577,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) {
@@ -616,19 +618,19 @@
   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;
   }
@@ -686,17 +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;
   }
-  Message* new_message = cmessage::GetMessageFactory()->GetPrototype(
-      from->message->GetDescriptor())->New();
+  Message* new_message = from->message->New();
   to->parent = NULL;
   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;
@@ -769,9 +770,7 @@
 
 PyTypeObject RepeatedScalarContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.pyext._message."
-  "RepeatedScalarContainer",           // tp_name
+  FULL_MODULE_NAME ".RepeatedScalarContainer",  // tp_name
   sizeof(RepeatedScalarContainer),     // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)repeated_scalar_container::Dealloc,  //  tp_dealloc
@@ -783,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
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h
index 5dfa21e..555e621 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.h
+++ b/python/google/protobuf/pyext/repeated_scalar_container.h
@@ -48,7 +48,11 @@
 
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
index 18ddd5c..a128cd4 100644
--- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -51,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 55e653a..0c75726 100755
--- a/python/google/protobuf/reflection.py
+++ b/python/google/protobuf/reflection.py
@@ -49,102 +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':
   from google.protobuf.pyext import cpp_message as message_impl
 else:
   from google.protobuf.internal import python_message as message_impl
 
-_NewMessage = message_impl.NewMessage
-_InitMessage = message_impl.InitMessage
-
-
-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)
-    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)
-    setattr(descriptor, '_concrete_class', cls)
+# 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 a47ce3e..8d25607 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,7 +74,27 @@
 
 
 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,
@@ -72,7 +104,8 @@
 
   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.
@@ -89,7 +122,7 @@
   Returns:
     A string of the text formatted protocol buffer message.
   """
-  out = cStringIO.StringIO()
+  out = TextWriter(as_utf8)
   PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line,
                pointy_brackets=pointy_brackets,
                use_index_order=use_index_order,
@@ -101,6 +134,12 @@
   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):
@@ -108,7 +147,19 @@
   if use_index_order:
     fields.sort(key=lambda x: x[0].index)
   for field, value in fields:
-    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+    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])
+        PrintField(field, entry_submsg, out, indent, as_utf8, as_one_line,
+                   pointy_brackets=pointy_brackets,
+                   use_index_order=use_index_order, float_format=float_format)
+    elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
       for element in value:
         PrintField(field, element, out, indent, as_utf8, as_one_line,
                    pointy_brackets=pointy_brackets,
@@ -124,14 +175,14 @@
 def PrintField(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 name/value pair.  For repeated fields, the value
-  should be a single element."""
+  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:
@@ -195,7 +246,7 @@
       out.write(str(value))
   elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
     out.write('\"')
-    if isinstance(value, unicode):
+    if isinstance(value, six.text_type):
       out_value = value.encode('utf-8')
     else:
       out_value = value
@@ -217,95 +268,113 @@
     out.write(str(value))
 
 
-def Parse(text, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def Parse(text, message, allow_unknown_extension=False):
+  """Parses an text representation of a protocol message into a message.
 
   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
 
   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)
 
 
-def Merge(text, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def Merge(text, message, allow_unknown_extension=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
 
   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)
 
 
-def ParseLines(lines, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def ParseLines(lines, message, allow_unknown_extension=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
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  _ParseOrMerge(lines, message, False)
+  _ParseOrMerge(lines, message, False, allow_unknown_extension)
   return message
 
 
-def MergeLines(lines, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def MergeLines(lines, message, allow_unknown_extension=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
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  _ParseOrMerge(lines, message, True)
+  _ParseOrMerge(lines, message, True, allow_unknown_extension)
   return message
 
 
-def _ParseOrMerge(lines, message, allow_multiple_scalars):
-  """Converts an ASCII representation of a protocol message into a message.
+def _ParseOrMerge(lines,
+                  message,
+                  allow_multiple_scalars,
+                  allow_unknown_extension=False):
+  """Converts an text representation of a protocol message into a message.
 
   Args:
-    lines: Lines of a message's ASCII representation.
+    lines: Lines of a message's 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".
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
   tokenizer = _Tokenizer(lines)
   while not tokenizer.AtEnd():
-    _MergeField(tokenizer, message, allow_multiple_scalars)
+    _MergeField(tokenizer, message, allow_multiple_scalars,
+                allow_unknown_extension)
 
 
-def _MergeField(tokenizer, message, allow_multiple_scalars):
+def _MergeField(tokenizer,
+                message,
+                allow_multiple_scalars,
+                allow_unknown_extension=False):
   """Merges a single protocol message field into a message.
 
   Args:
@@ -314,9 +383,11 @@
     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".
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Raises:
-    ParseError: In case of ASCII parsing problems.
+    ParseError: In case of text parsing problems.
   """
   message_descriptor = message.DESCRIPTOR
   if (hasattr(message_descriptor, 'syntax') and
@@ -338,13 +409,18 @@
     field = message.Extensions._FindExtensionByName(name)
     # pylint: enable=protected-access
     if not field:
-      raise tokenizer.ParseErrorPreviousToken(
-          'Extension "%s" not registered.' % name)
+      if 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()
     field = message_descriptor.fields_by_name.get(name, None)
@@ -366,7 +442,8 @@
           'Message type "%s" has no field named "%s".' % (
               message_descriptor.full_name, name))
 
-  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+  if field and field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+    is_map_entry = _IsMapEntry(field)
     tokenizer.TryConsume(':')
 
     if tokenizer.TryConsume('<'):
@@ -378,6 +455,8 @@
     if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
       if field.is_extension:
         sub_message = message.Extensions[field].add()
+      elif is_map_entry:
+        sub_message = field.message_type._concrete_class()
       else:
         sub_message = getattr(message, field.name).add()
     else:
@@ -390,9 +469,31 @@
     while not tokenizer.TryConsume(end_token):
       if tokenizer.AtEnd():
         raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
-      _MergeField(tokenizer, sub_message, allow_multiple_scalars)
-  else:
-    _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+      _MergeField(tokenizer, sub_message, allow_multiple_scalars,
+                  allow_unknown_extension)
+
+    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
+  elif field:
+    tokenizer.Consume(':')
+    if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and
+        tokenizer.TryConsume('[')):
+      # Short repeated format, e.g. "foo: [1, 2, 3]"
+      while True:
+        _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+        if tokenizer.TryConsume(']'):
+          break
+        tokenizer.Consume(',')
+    else:
+      _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+  else:  # Proto field is unknown.
+    assert allow_unknown_extension
+    _SkipFieldContents(tokenizer)
 
   # For historical reasons, fields may optionally be separated by commas or
   # semicolons.
@@ -400,6 +501,90 @@
     tokenizer.TryConsume(';')
 
 
+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:
+    _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.
+  if not tokenizer.TryConsume(','):
+    tokenizer.TryConsume(';')
+
+
+def _SkipFieldMessage(tokenizer):
+  """Skips over a field message.
+
+  Args:
+    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 an invalid field value is found.
+  """
+  # String tokens can come in multiple adjacent string literals.
+  # If we can consume one, consume as many as we can.
+  if tokenizer.TryConsumeString():
+    while tokenizer.TryConsumeString():
+      pass
+    return
+
+  if (not tokenizer.TryConsumeIdentifier() and
+      not tokenizer.TryConsumeInt64() and
+      not tokenizer.TryConsumeUint64() and
+      not tokenizer.TryConsumeFloat()):
+    raise ParseError('Invalid field value: ' + tokenizer.token)
+
+
 def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars):
   """Merges a single protocol message scalar field into a message.
 
@@ -412,10 +597,9 @@
       required/optional field named "foo".
 
   Raises:
-    ParseError: In case of ASCII parsing problems.
+    ParseError: In case of text parsing problems.
     RuntimeError: On runtime errors.
   """
-  tokenizer.Consume(':')
   value = None
 
   if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
@@ -469,7 +653,7 @@
 
 
 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.
@@ -478,11 +662,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):
@@ -499,6 +685,9 @@
     self._SkipWhitespace()
     self.NextToken()
 
+  def LookingAt(self, token):
+    return self.token == token
+
   def AtEnd(self):
     """Checks the end of the text was reached.
 
@@ -510,7 +699,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
@@ -554,6 +743,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.
 
@@ -580,7 +776,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
@@ -596,11 +792,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.
 
@@ -612,11 +815,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.
 
@@ -628,11 +838,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.
 
@@ -644,7 +861,7 @@
     """
     try:
       result = ParseFloat(self.token)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
@@ -660,11 +877,18 @@
     """
     try:
       result = ParseBool(self.token)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
 
+  def TryConsumeString(self):
+    try:
+      self.ConsumeString()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeString(self):
     """Consumes a string value.
 
@@ -676,8 +900,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):
@@ -690,10 +914,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.
@@ -701,17 +924,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 but found: "%r"' % text)
+    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
@@ -719,7 +947,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/setup.py b/python/setup.py
index c18818e..6ea3bad 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -1,34 +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
-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
+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']):
@@ -44,35 +34,38 @@
 else:
   protoc = find_executable("protoc")
 
+
 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.
+  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())
+    exec(version_file.read(), globals())
     return __version__
 
 
-def generate_proto(source):
+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")
@@ -83,25 +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("../src/google/protobuf/unittest_proto3_arena.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/internal/import_test_package/inner.proto")
-  generate_proto("google/protobuf/internal/import_test_package/outer.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)
+
 
 class clean(_clean):
   def run(self):
@@ -111,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)
@@ -121,91 +125,103 @@
     # 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)
+
 
 if __name__ == '__main__':
   ext_module_list = []
   cpp_impl = '--cpp_implementation'
+  warnings_as_errors = '--warnings_as_errors'
   if cpp_impl in sys.argv:
     sys.argv.remove(cpp_impl)
+    extra_compile_args = ['-Wno-write-strings', '-Wno-invalid-offsetof']
+    test_conformance.target = 'test_python_cpp'
+
+    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.append(Extension(
-        "google.protobuf.pyext._message",
-        [ "google/protobuf/pyext/descriptor.cc",
-          "google/protobuf/pyext/descriptor_containers.cc",
-          "google/protobuf/pyext/descriptor_pool.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' ],
-        ))
+    ext_module_list.append(
+        Extension(
+            "google.protobuf.pyext._message",
+            glob.glob('google/protobuf/pyext/*.cc'),
+            include_dirs=[".", "../src"],
+            libraries=['protobuf'],
+            library_dirs=['../src/.libs'],
+            extra_compile_args=extra_compile_args,
+        )
+    )
     os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
 
-  setup(name = 'protobuf',
-        version = GetVersion(),
-        packages = [ 'google' ],
-        namespace_packages = [ 'google' ],
-        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.proto_builder',
-          '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'],
-        # TODO: Restore dependency once a Python 3 compatible google-apputils
-        # is released.
-        setup_requires = (['google-apputils']
-                          if sys.version_info[0] < 3 else
-                          []),
-        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.",
-        )
+  # 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..27e5750
--- /dev/null
+++ b/ruby/Gemfile.lock
@@ -0,0 +1,30 @@
+PATH
+  remote: .
+  specs:
+    google-protobuf (3.0.0.alpha.5.0)
+
+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
index 8331d28..1647432 100644
--- a/ruby/README.md
+++ b/ruby/README.md
@@ -60,14 +60,28 @@
 * Ruby development headers
 * a C compiler
 
-First, install the required Ruby gems:
+To Build the JRuby extension, you will need:
 
-    $ sudo gem install bundler rake rake-compiler rspec rubygems-tasks
+* 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 gem
-    $ gem install pkg/protobuf-$VERSION.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
diff --git a/ruby/Rakefile b/ruby/Rakefile
index ae7d805..81c3119 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -1,20 +1,46 @@
-require "rake/extensiontask"
+require "rubygems"
+require "rubygems/package_task"
+require "rake/extensiontask" unless RUBY_PLATFORM == "java"
 require "rake/testtask"
 
 spec = Gem::Specification.load("google-protobuf.gemspec")
 
-Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
-  ext.ext_dir = "ext/google/protobuf_c"
-  ext.lib_dir = "lib/google"
+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 && rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.6"
+  end
+end
+
+Gem::PackageTask.new(spec) do |pkg|
 end
 
 Rake::TestTask.new(:test => :build) do |t|
   t.test_files = FileList["tests/*.rb"]
 end
 
-Gem::PackageTask.new(spec) do |pkg|
-end
-
 task :build => [:clean, :compile]
 task :default => [:build]
 
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index b39c27f..7e0cd14 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -34,8 +34,6 @@
 // Common utilities.
 // -----------------------------------------------------------------------------
 
-const char* kDescriptorInstanceVar = "descriptor";
-
 static const char* get_str(VALUE str) {
   Check_Type(str, T_STRING);
   return RSTRING_PTR(str);
@@ -90,7 +88,7 @@
     }                                                               \
 
 #define DEFINE_SELF(type, var, rb_var)                              \
-    type* var = ruby_to_ ## type(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.
@@ -250,7 +248,7 @@
                        &self->pb_serialize_handlers);
   }
   if (self->json_serialize_handlers) {
-    upb_handlers_unref(self->pb_serialize_handlers,
+    upb_handlers_unref(self->json_serialize_handlers,
                        &self->json_serialize_handlers);
   }
   xfree(self);
@@ -548,11 +546,9 @@
     rb_raise(rb_eArgError, "Expected symbol for field type.");
   }
 
-  upb_fieldtype_t upb_type = -1;
-
 #define CONVERT(upb, ruby)                                           \
   if (SYM2ID(type) == rb_intern( # ruby )) {                         \
-    upb_type = UPB_TYPE_ ## upb;                                     \
+    return UPB_TYPE_ ## upb;                                         \
   }
 
   CONVERT(FLOAT, float);
@@ -569,11 +565,8 @@
 
 #undef CONVERT
 
-  if (upb_type == -1) {
-    rb_raise(rb_eArgError, "Unknown field type.");
-  }
-
-  return upb_type;
+  rb_raise(rb_eArgError, "Unknown field type.");
+  return 0;
 }
 
 VALUE fieldtype_to_ruby(upb_fieldtype_t type) {
@@ -596,6 +589,68 @@
   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
@@ -611,7 +666,7 @@
   if (!upb_fielddef_typeisset(self->fielddef)) {
     return Qnil;
   }
-  return fieldtype_to_ruby(upb_fielddef_type(self->fielddef));
+  return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef));
 }
 
 /*
@@ -624,7 +679,7 @@
 VALUE FieldDescriptor_type_set(VALUE _self, VALUE type) {
   DEFINE_SELF(FieldDescriptor, self, _self);
   upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
-  upb_fielddef_settype(mut_def, ruby_to_fieldtype(type));
+  upb_fielddef_setdescriptortype(mut_def, ruby_to_descriptortype(type));
   return Qnil;
 }
 
@@ -663,15 +718,17 @@
 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.");
   }
 
-  upb_label_t upb_label = -1;
-
 #define CONVERT(upb, ruby)                                           \
   if (SYM2ID(label) == rb_intern( # ruby )) {                        \
     upb_label = UPB_LABEL_ ## upb;                                   \
+    converted = true;                                                \
   }
 
   CONVERT(OPTIONAL, optional);
@@ -680,7 +737,7 @@
 
 #undef CONVERT
 
-  if (upb_label == -1) {
+  if (!converted) {
     rb_raise(rb_eArgError, "Unknown field label.");
   }
 
@@ -745,10 +802,10 @@
 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.");
   }
-  const char* str = get_str(value);
   CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status),
             "Error setting submessage name");
   return Qnil;
@@ -765,10 +822,12 @@
  */
 VALUE FieldDescriptor_subtype(VALUE _self) {
   DEFINE_SELF(FieldDescriptor, self, _self);
+  const upb_def* def;
+
   if (!upb_fielddef_hassubdef(self->fielddef)) {
     return Qnil;
   }
-  const upb_def* def = upb_fielddef_subdef(self->fielddef);
+  def = upb_fielddef_subdef(self->fielddef);
   if (def == NULL) {
     return Qnil;
   }
@@ -1192,14 +1251,15 @@
  */
 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.");
   }
-  VALUE name = argv[0];
-  VALUE type = argv[1];
-  VALUE number = argv[2];
-  VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+  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);
@@ -1220,14 +1280,15 @@
  */
 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.");
   }
-  VALUE name = argv[0];
-  VALUE type = argv[1];
-  VALUE number = argv[2];
-  VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+  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);
@@ -1244,14 +1305,15 @@
  */
 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.");
   }
-  VALUE name = argv[0];
-  VALUE type = argv[1];
-  VALUE number = argv[2];
-  VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+  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);
@@ -1271,15 +1333,17 @@
  */
 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.");
   }
-  VALUE name = argv[0];
-  VALUE key_type = argv[1];
-  VALUE value_type = argv[2];
-  VALUE number = argv[3];
-  VALUE type_class = (argc > 4) ? argv[4] : Qnil;
+  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
@@ -1295,55 +1359,67 @@
 
   // Create a new message descriptor for the map entry message, and create a
   // repeated submessage field here with that type.
-  VALUE mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor);
-  VALUE mapentry_desc_name = rb_funcall(self->descriptor, rb_intern("name"), 0);
+  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 name absolute.
-    submsg_name = rb_str_append(submsg_name, type_class);
-    FieldDescriptor_submsg_name_set(value_field, submsg_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);
   }
-  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);
+  {
+    // 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);
+  }
 
-  VALUE map_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
-  VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(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")));
-  VALUE 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);
+  {
+    // 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;
 }
@@ -1439,14 +1515,15 @@
  */
 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.");
   }
-  VALUE name = argv[0];
-  VALUE type = argv[1];
-  VALUE number = argv[2];
-  VALUE type_class = (argc > 3) ? argv[3] : Qnil;
+  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);
@@ -1590,9 +1667,9 @@
  * 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.
+ * 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.
  */
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
index 5730504..1c48281 100644
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -30,6 +30,20 @@
 
 #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.
 // -----------------------------------------------------------------------------
@@ -164,7 +178,7 @@
                                  const char* str, size_t len,
                                  const upb_bufhandle* handle) {
   VALUE rb_str = (VALUE)closure;
-  rb_str_cat(rb_str, str, len);
+  noleak_rb_str_cat(rb_str, str, len);
   return len;
 }
 
@@ -175,11 +189,11 @@
   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);
 
-  MessageHeader* submsg;
   TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
   return submsg;
 }
@@ -191,14 +205,15 @@
   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);
   }
 
-  VALUE submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
-  MessageHeader* submsg;
+  submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
   TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
   return submsg;
 }
@@ -254,12 +269,14 @@
       &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 value = native_slot_get(
+  value = native_slot_get(
       mapdata->value_field_type, value_field_typeclass,
       &frame->value_storage);
 
@@ -280,15 +297,14 @@
     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;
-  const upb_fielddef* key_field = upb_msgdef_itof(mapentry_def,
-                                                  MAP_KEY_FIELD);
+  key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
   assert(key_field != NULL);
   hd->key_field_type = upb_fielddef_type(key_field);
-  const upb_fielddef* value_field = upb_msgdef_itof(mapentry_def,
-                                                    MAP_VALUE_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);
@@ -354,6 +370,8 @@
   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) {
@@ -369,8 +387,7 @@
   DEREF(msg, oneofdata->case_ofs, uint32_t) =
       oneofdata->oneof_case_num;
 
-  VALUE submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
-  MessageHeader* submsg;
+  submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
   TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
   return submsg;
 }
@@ -465,8 +482,9 @@
                                       Descriptor* desc) {
   const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
   map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
-  upb_handlers_addcleanup(h, hd, free);
   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);
@@ -479,8 +497,9 @@
   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_handlers_addcleanup(h, hd, free);
   upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+
+  upb_handlers_addcleanup(h, hd, free);
   upb_handlerattr_sethandlerdata(&attr, hd);
   upb_handlers_setendmsg(h, endmap_handler, &attr);
 
@@ -542,6 +561,7 @@
 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.
@@ -558,7 +578,6 @@
     desc->layout = create_layout(desc->msgdef);
   }
 
-  upb_msg_field_iter i;
   for (upb_msg_field_begin(&i, desc->msgdef);
        !upb_msg_field_done(&i);
        upb_msg_field_next(&i)) {
@@ -610,8 +629,7 @@
   upb_pbdecodermethodopts opts;
   upb_pbdecodermethodopts_init(&opts, handlers);
 
-  const upb_pbdecodermethod *ret = upb_pbdecodermethod_new(&opts, owner);
-  return ret;
+  return upb_pbdecodermethod_new(&opts, owner);
 }
 
 static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
@@ -622,6 +640,51 @@
   return desc->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;
+  upb_seededalloc alloc;
+  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_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);
+}
+
 /*
  * call-seq:
  *     MessageClass.decode(data) => message
@@ -631,34 +694,33 @@
  * and returns a message object with the corresponding field values.
  */
 VALUE Message_decode(VALUE klass, VALUE data) {
-  VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+  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.");
   }
 
-  VALUE msg_rb = rb_class_new_instance(0, NULL, msgklass);
-  MessageHeader* msg;
+  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);
-  upb_pbdecoder decoder;
-  upb_sink sink;
-  upb_status status = UPB_STATUS_INIT;
+  {
+    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_pbdecoder_init(&decoder, method, &status);
-  upb_sink_reset(&sink, h, msg);
-  upb_pbdecoder_resetoutput(&decoder, &sink);
-  upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
-                    upb_pbdecoder_input(&decoder));
+    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));
 
-  upb_pbdecoder_uninit(&decoder);
-  if (!upb_ok(&status)) {
-    rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.",
-             upb_status_errmsg(&status));
+    stackenv_uninit(&se);
   }
 
   return msg_rb;
@@ -673,9 +735,11 @@
  * and returns a message object with the corresponding field values.
  */
 VALUE Message_decode_json(VALUE klass, VALUE data) {
-  VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+  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.");
@@ -684,24 +748,21 @@
   // convert, because string handlers pass data directly to message string
   // fields.
 
-  VALUE msg_rb = rb_class_new_instance(0, NULL, msgklass);
-  MessageHeader* msg;
+  msg_rb = rb_class_new_instance(0, NULL, msgklass);
   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
 
-  upb_status status = UPB_STATUS_INIT;
-  upb_json_parser parser;
-  upb_json_parser_init(&parser, &status);
+  {
+    stackenv se;
+    upb_sink sink;
+    upb_json_parser* parser;
+    stackenv_init(&se, "Error occurred during parsing: %s");
 
-  upb_sink sink;
-  upb_sink_reset(&sink, get_fill_handlers(desc), msg);
-  upb_json_parser_resetoutput(&parser, &sink);
-  upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
-                    upb_json_parser_input(&parser));
+    upb_sink_reset(&sink, get_fill_handlers(desc), msg);
+    parser = upb_json_parser_create(&se.env, &sink);
+    upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
+                      upb_json_parser_input(parser));
 
-  upb_json_parser_uninit(&parser);
-  if (!upb_ok(&status)) {
-    rb_raise(rb_eRuntimeError, "Error occurred during parsing: %s.",
-             upb_status_errmsg(&status));
+    stackenv_uninit(&se);
   }
 
   return msg_rb;
@@ -733,12 +794,12 @@
 
 static size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
                                 size_t len, const upb_bufhandle *handle) {
-  UPB_UNUSED(hd);
-  UPB_UNUSED(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;
   }
@@ -792,10 +853,11 @@
 }
 
 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);
-  upb_sink subsink;
 
   // 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.
@@ -810,11 +872,14 @@
 
 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;
 
-  upb_sink subsink;
-  VALUE descriptor = rb_iv_get(submsg, kDescriptorInstanceVar);
-  Descriptor* subdesc = ruby_to_Descriptor(descriptor);
+  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);
@@ -823,19 +888,20 @@
 
 static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
                    int depth) {
-  if (ary == Qnil) return;
-
   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);
 
-  upb_fieldtype_t type = upb_fielddef_type(f);
-  upb_selector_t sel = 0;
   if (upb_fielddef_isprimitive(f)) {
     sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
   }
 
-  int size = NUM2INT(RepeatedField_length(ary));
+  size = NUM2INT(RepeatedField_length(ary));
   for (int i = 0; i < size; i++) {
     void* memory = RepeatedField_index_native(ary, i);
     switch (type) {
@@ -918,31 +984,35 @@
 
 static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
                    int depth) {
-  if (map == Qnil) return;
-  Map* self = ruby_to_Map(map);
-
+  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);
-  const upb_fielddef* key_field = map_field_key(f);
-  const upb_fielddef* value_field = map_field_value(f);
+  key_field = map_field_key(f);
+  value_field = map_field_value(f);
 
-  Map_iter it;
   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_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_status status;
     upb_sink_endmsg(&entry_sink, &status);
     upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
   }
@@ -952,19 +1022,21 @@
 
 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 > UPB_SINK_MAX_NESTING) {
+  if (depth > ENCODE_MAX_NESTING) {
     rb_raise(rb_eRuntimeError,
              "Maximum recursion depth exceeded during encoding.");
   }
 
-  MessageHeader* msg;
   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
 
-  upb_msg_field_iter i;
   for (upb_msg_field_begin(&i, desc->msgdef);
        !upb_msg_field_done(&i);
        upb_msg_field_next(&i)) {
@@ -1036,7 +1108,6 @@
     }
   }
 
-  upb_status status;
   upb_sink_endmsg(sink, &status);
 }
 
@@ -1065,27 +1136,32 @@
  * wire format.
  */
 VALUE Message_encode(VALUE klass, VALUE msg_rb) {
-  VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+  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);
+  {
+    const upb_handlers* serialize_handlers =
+        msgdef_pb_serialize_handlers(desc);
 
-  upb_pb_encoder encoder;
-  upb_pb_encoder_init(&encoder, serialize_handlers);
-  upb_pb_encoder_resetoutput(&encoder, &sink.sink);
+    stackenv se;
+    upb_pb_encoder* encoder;
+    VALUE ret;
 
-  putmsg(msg_rb, desc, upb_pb_encoder_input(&encoder), 0);
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
 
-  VALUE ret = rb_str_new(sink.ptr, sink.len);
+    putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0);
 
-  upb_pb_encoder_uninit(&encoder);
-  stringsink_uninit(&sink);
+    ret = rb_str_new(sink.ptr, sink.len);
 
-  return ret;
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
+
+    return ret;
+  }
 }
 
 /*
@@ -1095,73 +1171,30 @@
  * Encodes the given message object into its serialized JSON representation.
  */
 VALUE Message_encode_json(VALUE klass, VALUE msg_rb) {
-  VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+  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_json_serialize_handlers(desc);
+  {
+    const upb_handlers* serialize_handlers =
+        msgdef_json_serialize_handlers(desc);
+    upb_json_printer* printer;
+    stackenv se;
+    VALUE ret;
 
-  upb_json_printer printer;
-  upb_json_printer_init(&printer, serialize_handlers);
-  upb_json_printer_resetoutput(&printer, &sink.sink);
+    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);
+    putmsg(msg_rb, desc, upb_json_printer_input(printer), 0);
 
-  VALUE ret = rb_str_new(sink.ptr, sink.len);
+    ret = rb_str_new(sink.ptr, sink.len);
 
-  upb_json_printer_uninit(&printer);
-  stringsink_uninit(&sink);
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
 
-  return ret;
+    return ret;
+  }
 }
 
-/*
- * call-seq:
- *     Google::Protobuf.encode(msg) => bytes
- *
- * Encodes the given message object to protocol buffers wire format. This is an
- * alternative to the #encode method on msg's class.
- */
-VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb) {
-  VALUE klass = CLASS_OF(msg_rb);
-  return Message_encode(klass, msg_rb);
-}
-
-/*
- * call-seq:
- *     Google::Protobuf.encode_json(msg) => json_string
- *
- * Encodes the given message object to its JSON representation. This is an
- * alternative to the #encode_json method on msg's class.
- */
-VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb) {
-  VALUE klass = CLASS_OF(msg_rb);
-  return Message_encode_json(klass, msg_rb);
-}
-
-/*
- * call-seq:
- *     Google::Protobuf.decode(class, bytes) => msg
- *
- * Decodes the given bytes as protocol buffers wire format under the
- * interpretation given by the given class's message definition. This is an
- * alternative to the #decode method on the given class.
- */
-VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb) {
-  return Message_decode(klass, msg_rb);
-}
-
-/*
- * call-seq:
- *     Google::Protobuf.decode_json(class, json_string) => msg
- *
- * Decodes the given JSON string under the interpretation given by the given
- * class's message definition. This is an alternative to the #decode_json method
- * on the given class.
- */
-VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb) {
-  return Message_decode_json(klass, msg_rb);
-}
diff --git a/ruby/ext/google/protobuf_c/extconf.rb b/ruby/ext/google/protobuf_c/extconf.rb
index 8d60392..b368dcc 100644
--- a/ruby/ext/google/protobuf_c/extconf.rb
+++ b/ruby/ext/google/protobuf_c/extconf.rb
@@ -2,7 +2,7 @@
 
 require 'mkmf'
 
-$CFLAGS += " -O3 -std=c99 -Wno-unused-function -DNDEBUG "
+$CFLAGS += " -std=c99 -O3 -DNDEBUG"
 
 $objs = ["protobuf.o", "defs.o", "storage.o", "message.o",
          "repeated_field.o", "map.o", "encode_decode.o", "upb.o"]
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
index 12e7a9d..92fc728 100644
--- a/ruby/ext/google/protobuf_c/map.c
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -120,7 +120,7 @@
 }
 
 static void* value_memory(upb_value* v) {
-  return (void*)(&v->val.uint64);
+  return (void*)(&v->val);
 }
 
 // -----------------------------------------------------------------------------
@@ -169,8 +169,7 @@
   Map* self = ALLOC(Map);
   memset(self, 0, sizeof(Map));
   self->value_type_class = Qnil;
-  VALUE ret = TypedData_Wrap_Struct(klass, &Map_type, self);
-  return ret;
+  return TypedData_Wrap_Struct(klass, &Map_type, self);
 }
 
 static bool needs_typeclass(upb_fieldtype_t type) {
@@ -215,6 +214,7 @@
  */
 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
@@ -241,7 +241,7 @@
       rb_raise(rb_eArgError, "Invalid key type for map.");
   }
 
-  int init_value_arg = 2;
+  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);
@@ -356,9 +356,9 @@
   char keybuf[TABLE_KEY_BUF_LENGTH];
   const char* keyval = NULL;
   size_t length = 0;
+  upb_value v;
   table_key(self, key, keybuf, &keyval, &length);
 
-  upb_value v;
   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);
@@ -381,10 +381,11 @@
   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);
 
-  upb_value v;
-  void* mem = value_memory(&v);
+  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.
@@ -432,9 +433,9 @@
   char keybuf[TABLE_KEY_BUF_LENGTH];
   const char* keyval = NULL;
   size_t length = 0;
+  upb_value v;
   table_key(self, key, keybuf, &keyval, &length);
 
-  upb_value v;
   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);
@@ -564,6 +565,8 @@
  */
 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.
@@ -573,7 +576,7 @@
     _other = other_map;
   }
 
-  Map* other = ruby_to_Map(_other);
+  other = ruby_to_Map(_other);
 
   if (self == other) {
     return Qtrue;
@@ -589,7 +592,6 @@
 
   // For each member of self, check that an equal member exists at the same key
   // in other.
-  upb_strtable_iter it;
   for (upb_strtable_begin(&it, &self->table);
        !upb_strtable_done(&it);
        upb_strtable_next(&it)) {
@@ -719,6 +721,7 @@
 
     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 ||
@@ -726,19 +729,19 @@
       rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
     }
 
-    upb_strtable_iter it;
     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);
 
-      upb_value v = upb_strtable_iter_value(&it);
+      v = upb_strtable_iter_value(&it);
       upb_strtable_insert2(&self->table,
                            upb_strtable_iter_key(&it),
                            upb_strtable_iter_keylength(&it),
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index 7e58a61..283939c 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -53,17 +53,19 @@
 };
 
 VALUE Message_alloc(VALUE klass) {
-  VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
+  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().
-  VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
+  ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
   msg->descriptor = desc;
-  rb_iv_set(ret, kDescriptorInstanceVar, descriptor);
+  rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
 
   layout_init(desc->layout, Message_data(msg));
 
@@ -71,29 +73,34 @@
 }
 
 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_iter it;
   upb_oneof_begin(&it, o);
   assert(!upb_oneof_done(&it));
-  const upb_fielddef* first_field = upb_oneof_iter_field(&it);
+  first_field = upb_oneof_iter_field(&it);
   assert(upb_fielddef_containingoneof(first_field) != NULL);
 
-  size_t case_ofs =
+  case_ofs =
       self->descriptor->layout->
       fields[upb_fielddef_index(first_field)].case_offset;
-  uint32_t oneof_case = *((uint32_t*)(Message_data(self) + case_ofs));
+  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.
-  const upb_fielddef* f = upb_oneofdef_itof(o, oneof_case);
+  f = upb_oneofdef_itof(o, oneof_case);
   assert(f != NULL);
 
   return ID2SYM(rb_intern(upb_fielddef_name(f)));
@@ -118,18 +125,25 @@
  */
 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.");
   }
-  VALUE method_name = argv[0];
+  method_name = argv[0];
   if (!SYMBOL_P(method_name)) {
     rb_raise(rb_eArgError, "Expected symbol as method name.");
   }
-  VALUE method_str = rb_id2str(SYM2ID(method_name));
-  char* name = RSTRING_PTR(method_str);
-  size_t name_len = RSTRING_LEN(method_str);
-  bool setter = false;
+  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] == '=') {
@@ -138,7 +152,7 @@
   }
 
   // Check for a oneof name first.
-  const upb_oneofdef* o = upb_msgdef_ntoo(self->descriptor->msgdef,
+  o = upb_msgdef_ntoo(self->descriptor->msgdef,
                                           name, name_len);
   if (o != NULL) {
     if (setter) {
@@ -148,11 +162,11 @@
   }
 
   // Otherwise, check for a field with that name.
-  const upb_fielddef* f = upb_msgdef_ntof(self->descriptor->msgdef,
+  f = upb_msgdef_ntof(self->descriptor->msgdef,
                                           name, name_len);
 
   if (f == NULL) {
-    rb_raise(rb_eArgError, "Unknown field");
+    return rb_call_super(argc, argv);
   }
 
   if (setter) {
@@ -168,6 +182,9 @@
 
 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)) {
@@ -175,27 +192,31 @@
              "Expected symbols as hash keys in initialization map.");
   }
 
-  VALUE method_str = rb_id2str(SYM2ID(key));
-  char* name = RSTRING_PTR(method_str);
-  const upb_fielddef* f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
+  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 in initialization map entry.");
+             "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.");
+               "Expected Hash object as initializer value for map field '%s'.", name);
     }
-    VALUE map = layout_get(self->descriptor->layout, Message_data(self), f);
+    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.");
+               "Expected array as initializer value for repeated field '%s'.", name);
     }
-    VALUE ary = layout_get(self->descriptor->layout, Message_data(self), f);
+    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));
     }
@@ -218,13 +239,15 @@
  * 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.");
   }
-  VALUE hash_args = argv[0];
+  hash_args = argv[0];
   if (TYPE(hash_args) != T_HASH) {
     rb_raise(rb_eArgError, "Expected hash arguments.");
   }
@@ -241,10 +264,11 @@
  */
 VALUE Message_dup(VALUE _self) {
   MessageHeader* self;
+  VALUE new_msg;
+  MessageHeader* new_msg_self;
   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
 
-  VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
-  MessageHeader* new_msg_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,
@@ -257,10 +281,11 @@
 // 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);
 
-  VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
-  MessageHeader* new_msg_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,
@@ -281,9 +306,8 @@
  */
 VALUE Message_eq(VALUE _self, VALUE _other) {
   MessageHeader* self;
-  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
-
   MessageHeader* other;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
   TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
 
   if (self->descriptor != other->descriptor) {
@@ -318,9 +342,10 @@
  */
 VALUE Message_inspect(VALUE _self) {
   MessageHeader* self;
+  VALUE str;
   TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
 
-  VALUE str = rb_str_new2("<");
+  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(
@@ -329,6 +354,32 @@
   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
@@ -338,10 +389,10 @@
  */
 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);
-  const upb_fielddef* field =
-      upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
   if (field == NULL) {
     return Qnil;
   }
@@ -357,10 +408,10 @@
  */
 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);
-  const upb_fielddef* field =
-      upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+  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));
   }
@@ -376,10 +427,13 @@
  * message class's type.
  */
 VALUE Message_descriptor(VALUE klass) {
-  return rb_iv_get(klass, kDescriptorInstanceVar);
+  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);
   }
@@ -387,18 +441,24 @@
     desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
   }
 
-  const char* name = upb_msgdef_fullname(desc->msgdef);
+  name = upb_msgdef_fullname(desc->msgdef);
   if (name == NULL) {
     rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
   }
 
-  VALUE klass = rb_define_class_id(
+  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_iv_set(klass, kDescriptorInstanceVar, get_def_obj(desc->msgdef));
+  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);
@@ -407,6 +467,8 @@
   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);
@@ -415,6 +477,7 @@
   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;
 }
 
@@ -427,7 +490,7 @@
  */
 VALUE enum_lookup(VALUE self, VALUE number) {
   int32_t num = NUM2INT(number);
-  VALUE desc = rb_iv_get(self, kDescriptorInstanceVar);
+  VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
 
   const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
@@ -447,7 +510,7 @@
  */
 VALUE enum_resolve(VALUE self, VALUE sym) {
   const char* name = rb_id2name(SYM2ID(sym));
-  VALUE desc = rb_iv_get(self, kDescriptorInstanceVar);
+  VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
   EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
 
   int32_t num = 0;
@@ -467,7 +530,7 @@
  * EnumDescriptor corresponding to this enum type.
  */
 VALUE enum_descriptor(VALUE self) {
-  return rb_iv_get(self, kDescriptorInstanceVar);
+  return rb_ivar_get(self, descriptor_instancevar_interned);
 }
 
 VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
@@ -492,7 +555,8 @@
   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_iv_set(mod, kDescriptorInstanceVar, get_def_obj(enumdesc->enumdef));
+  rb_ivar_set(mod, descriptor_instancevar_interned,
+              get_def_obj(enumdesc->enumdef));
 
   return mod;
 }
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index d2d3503..7cde4ae 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -39,6 +39,9 @@
 // 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);
 }
@@ -64,6 +67,15 @@
 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.
 // -----------------------------------------------------------------------------
@@ -74,6 +86,8 @@
   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);
@@ -86,12 +100,8 @@
   RepeatedField_register(protobuf);
   Map_register(protobuf);
 
-  rb_define_singleton_method(protobuf, "encode", Google_Protobuf_encode, 1);
-  rb_define_singleton_method(protobuf, "decode", Google_Protobuf_decode, 2);
-  rb_define_singleton_method(protobuf, "encode_json",
-                             Google_Protobuf_encode_json, 1);
-  rb_define_singleton_method(protobuf, "decode_json",
-                             Google_Protobuf_decode_json, 2);
+  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);
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index d8a327a..8750c93 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -161,7 +161,8 @@
 extern VALUE cEnumBuilderContext;
 extern VALUE cBuilder;
 
-extern const char* kDescriptorInstanceVar;
+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
@@ -361,19 +362,20 @@
 RepeatedField* ruby_to_RepeatedField(VALUE value);
 
 VALUE RepeatedField_each(VALUE _self);
-VALUE RepeatedField_index(VALUE _self, VALUE _index);
+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(VALUE _self);
+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);
@@ -497,11 +499,6 @@
 VALUE Message_decode_json(VALUE klass, VALUE data);
 VALUE Message_encode_json(VALUE klass, VALUE msg_rb);
 
-VALUE Google_Protobuf_encode(VALUE self, VALUE msg_rb);
-VALUE Google_Protobuf_decode(VALUE self, VALUE klass, VALUE msg_rb);
-VALUE Google_Protobuf_encode_json(VALUE self, VALUE msg_rb);
-VALUE Google_Protobuf_decode_json(VALUE self, VALUE klass, VALUE msg_rb);
-
 VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
 
 VALUE build_module_from_enumdesc(EnumDescriptor* enumdef);
@@ -511,6 +508,10 @@
 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.
@@ -530,4 +531,6 @@
     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
index 8cf2e29..83afbc9 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.c
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -47,6 +47,34 @@
   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)
@@ -67,29 +95,57 @@
     VALUE val = native_slot_get(field_type, field_type_class, memory);
     rb_yield(val);
   }
-  return Qnil;
+  return _self;
 }
 
+
 /*
  * call-seq:
  *     RepeatedField.[](index) => value
  *
- * Accesses the element at the given index. Throws an exception on out-of-bounds
- * errors.
+ * Accesses the element at the given index. Returns nil on out-of-bounds
  */
-VALUE RepeatedField_index(VALUE _self, VALUE _index) {
+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;
 
-  int index = NUM2INT(_index);
-  if (index < 0 || index >= self->size) {
-    rb_raise(rb_eRangeError, "Index out of range");
-  }
+  VALUE arg = argv[0];
+  long beg, len;
 
-  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
-  return native_slot_get(field_type, field_type_class, memory);
+  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);
 }
 
 /*
@@ -104,23 +160,24 @@
   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 = NUM2INT(_index);
+  int index = index_position(_index, self);
   if (index < 0 || index >= (INT_MAX - 1)) {
-    rb_raise(rb_eRangeError, "Index out of range");
+    return Qnil;
   }
   if (index >= self->size) {
-    RepeatedField_reserve(self, index + 1);
     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 = (void *)(((uint8_t *)self->elements) + i * element_size);
+      void* elem = RepeatedField_memoryat(self, i, element_size);
       native_slot_init(field_type, elem);
     }
     self->size = index + 1;
   }
 
-  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+  memory = RepeatedField_memoryat(self, index, element_size);
   native_slot_set(field_type, field_type_class, memory, val);
   return Qnil;
 }
@@ -128,6 +185,8 @@
 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;
   }
@@ -137,8 +196,6 @@
   while (self->capacity < new_size) {
     self->capacity *= 2;
   }
-  void* old_elems = self->elements;
-  int elem_size = native_slot_size(self->field_type);
   self->elements = ALLOC_N(uint8_t, elem_size * self->capacity);
   if (old_elems != NULL) {
     memcpy(self->elements, old_elems, self->size * elem_size);
@@ -156,23 +213,26 @@
   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);
-  int index = self->size;
-  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+  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 index only after set.
+  // 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);
-  int index = self->size;
-  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
+  memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
   memcpy(memory, data, element_size);
   self->size++;
 }
@@ -181,46 +241,33 @@
   RepeatedField* self = ruby_to_RepeatedField(_self);
   upb_fieldtype_t field_type = self->field_type;
   int element_size = native_slot_size(field_type);
-  return ((uint8_t *)self->elements) + index * element_size;
+  return RepeatedField_memoryat(self, index, element_size);
 }
 
 /*
- * call-seq:
- *     RepeatedField.pop => value
- *
- * Removes the last element and returns it. Throws an exception if the repeated
- * field is empty.
+ * Private ruby method, used by RepeatedField.pop
  */
-VALUE RepeatedField_pop(VALUE _self) {
+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) {
-    rb_raise(rb_eRangeError, "Pop from empty repeated field is not allowed.");
+    return Qnil;
   }
-  int index = self->size - 1;
-  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
-  VALUE ret = native_slot_get(field_type, field_type_class, memory);
+  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.insert(*args)
- *
- * Pushes each arg in turn onto the end of the repeated field.
- */
-VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self) {
-  for (int i = 0; i < argc; i++) {
-    RepeatedField_push(_self, argv[i]);
-  }
-  return Qnil;
-}
-
-/*
- * call-seq:
  *     RepeatedField.replace(list)
  *
  * Replaces the contents of the repeated field with the given list of elements.
@@ -232,7 +279,7 @@
   for (int i = 0; i < RARRAY_LEN(list); i++) {
     RepeatedField_push(_self, rb_ary_entry(list, i));
   }
-  return Qnil;
+  return list;
 }
 
 /*
@@ -244,7 +291,7 @@
 VALUE RepeatedField_clear(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
   self->size = 0;
-  return Qnil;
+  return _self;
 }
 
 /*
@@ -283,10 +330,10 @@
   RepeatedField* self = ruby_to_RepeatedField(_self);
   VALUE new_rptfield = RepeatedField_new_this_type(_self);
   RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
-  RepeatedField_reserve(new_rptfield_self, self->size);
   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;
@@ -302,10 +349,10 @@
   RepeatedField* self = ruby_to_RepeatedField(_self);
   VALUE new_rptfield = RepeatedField_new_this_type(_self);
   RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
-  RepeatedField_reserve(new_rptfield_self, self->size);
   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;
@@ -333,7 +380,6 @@
   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;
@@ -353,34 +399,39 @@
  * indicated that every element has equal value.
  */
 VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
+  RepeatedField* self;
+  RepeatedField* other;
+
   if (_self == _other) {
     return Qtrue;
   }
-  RepeatedField* self = ruby_to_RepeatedField(_self);
 
   if (TYPE(_other) == T_ARRAY) {
     VALUE self_ary = RepeatedField_to_ary(_self);
     return rb_equal(self_ary, _other);
   }
 
-  RepeatedField* other = ruby_to_RepeatedField(_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;
+  {
+    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;
   }
-  return Qtrue;
 }
 
 /*
@@ -411,19 +462,6 @@
 
 /*
  * call-seq:
- *     RepeatedField.inspect => string
- *
- * Returns a string representing this repeated field's elements. It will be
- * formated as "[<element>, <element>, ...]", with each element's string
- * representation computed by its own #inspect method.
- */
-VALUE RepeatedField_inspect(VALUE _self) {
-  VALUE self_ary = RepeatedField_to_ary(_self);
-  return rb_funcall(self_ary, rb_intern("inspect"), 0);
-}
-
-/*
- * call-seq:
  *     RepeatedField.+(other) => repeated field
  *
  * Returns a new repeated field that contains the concatenated list of this
@@ -458,14 +496,29 @@
   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_iv_get(klass, kDescriptorInstanceVar) == Qnil) {
+  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_iv_get(klass, kDescriptorInstanceVar);
+    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.");
@@ -475,7 +528,7 @@
                "Message class was not returned by the DescriptorPool.");
     }
   } else if (type == UPB_TYPE_ENUM) {
-    VALUE enumdesc = rb_iv_get(klass, kDescriptorInstanceVar);
+    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.");
@@ -525,9 +578,9 @@
 
 void RepeatedField_mark(void* _self) {
   RepeatedField* self = (RepeatedField*)_self;
-  rb_gc_mark(self->field_type_class);
   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);
@@ -558,8 +611,7 @@
   self->capacity = 0;
   self->field_type = -1;
   self->field_type_class = Qnil;
-  VALUE ret = TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
-  return ret;
+  return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
 }
 
 VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) {
@@ -577,22 +629,23 @@
   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, "[]", 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_method(klass, "pop", RepeatedField_pop, 0);
-  rb_define_method(klass, "insert", RepeatedField_insert, -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, "inspect", RepeatedField_inspect, 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
index 5b1549d..b1f65f4 100644
--- a/ruby/ext/google/protobuf_c/storage.c
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -155,7 +155,9 @@
       break;
     }
     case UPB_TYPE_MESSAGE: {
-      if (CLASS_OF(value) != type_class) {
+      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)));
@@ -164,11 +166,11 @@
       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.");
       }
-      int32_t int_val = 0;
       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);
@@ -344,24 +346,33 @@
 // Map field utilities.
 // -----------------------------------------------------------------------------
 
-bool is_map_field(const upb_fielddef* field) {
+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 false;
+    return NULL;
   }
-  const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
-  return upb_msgdef_mapentry(subdef);
+  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) {
-  assert(is_map_field(field));
-  const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
+  const upb_msgdef* subdef = map_entry_msgdef(field);
   return map_entry_key(subdef);
 }
 
 const upb_fielddef* map_field_value(const upb_fielddef* field) {
-  assert(is_map_field(field));
-  const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
+  const upb_msgdef* subdef = map_entry_msgdef(field);
   return map_entry_value(subdef);
 }
 
@@ -389,14 +400,17 @@
 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);
 
-  upb_msg_field_iter it;
-  size_t off = 0;
   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.
@@ -404,7 +418,7 @@
     }
 
     // Allocate |field_size| bytes for this field in the layout.
-    size_t field_size = 0;
+    field_size = 0;
     if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
       field_size = sizeof(VALUE);
     } else {
@@ -413,7 +427,8 @@
     // 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;
+    layout->fields[upb_fielddef_index(field)].case_offset =
+        MESSAGE_FIELD_NO_CASE;
     off += field_size;
   }
 
@@ -430,11 +445,11 @@
   // 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.
-  upb_msg_oneof_iter oit;
   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.
@@ -442,7 +457,6 @@
     // Align the offset.
     off = align_up_to(off, field_size);
     // Assign all fields in the oneof this same offset.
-    upb_oneof_iter fit;
     for (upb_oneof_begin(&fit, oneof);
          !upb_oneof_done(&fit);
          upb_oneof_next(&fit)) {
@@ -457,12 +471,12 @@
        !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.
-    upb_oneof_iter fit;
     for (upb_oneof_begin(&fit, oneof);
          !upb_oneof_done(&fit);
          upb_oneof_next(&fit)) {
@@ -538,6 +552,7 @@
 }
 
 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) ||
@@ -545,7 +560,7 @@
     rb_raise(rb_eTypeError, "Expected repeated field array");
   }
 
-  RepeatedField* self = ruby_to_RepeatedField(val);
+  self = ruby_to_RepeatedField(val);
   if (self->field_type != upb_fielddef_type(field)) {
     rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
   }
@@ -561,16 +576,16 @@
 }
 
 static void check_map_field_type(VALUE val, const upb_fielddef* field) {
-  assert(is_map_field(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");
   }
 
-  Map* self = ruby_to_Map(val);
+  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");
   }
diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c
index 20bd76b..9e6aa67 100644
--- a/ruby/ext/google/protobuf_c/upb.c
+++ b/ruby/ext/google/protobuf_c/upb.c
@@ -1,11 +1,5 @@
 // Amalgamated source file
 #include "upb.h"
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2008-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
 
 
 #include <stdlib.h>
@@ -13,7 +7,7 @@
 
 typedef struct {
   size_t len;
-  char str[1];  // Null-terminated string data follows.
+  char str[1];  /* Null-terminated string data follows. */
 } str_t;
 
 static str_t *newstr(const char *data, size_t len) {
@@ -27,7 +21,7 @@
 
 static void freestr(str_t *s) { free(s); }
 
-// isalpha() etc. from <ctype.h> are locale-dependent, which we don't want.
+/* 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;
 }
@@ -42,7 +36,8 @@
 
 static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) {
   bool start = true;
-  for (size_t i = 0; i < len; i++) {
+  size_t i;
+  for (i = 0; i < len; i++) {
     char c = str[i];
     if (c == '.') {
       if (start || !full) {
@@ -87,39 +82,22 @@
 upb_def *upb_def_dup(const upb_def *def, const void *o) {
   switch (def->type) {
     case UPB_DEF_MSG:
-      return UPB_UPCAST(upb_msgdef_dup(upb_downcast_msgdef(def), o));
+      return upb_msgdef_upcast_mutable(
+          upb_msgdef_dup(upb_downcast_msgdef(def), o));
     case UPB_DEF_FIELD:
-      return UPB_UPCAST(upb_fielddef_dup(upb_downcast_fielddef(def), o));
+      return upb_fielddef_upcast_mutable(
+          upb_fielddef_dup(upb_downcast_fielddef(def), o));
     case UPB_DEF_ENUM:
-      return UPB_UPCAST(upb_enumdef_dup(upb_downcast_enumdef(def), o));
+      return upb_enumdef_upcast_mutable(
+          upb_enumdef_dup(upb_downcast_enumdef(def), o));
     default: assert(false); return NULL;
   }
 }
 
-bool upb_def_isfrozen(const upb_def *def) {
-  return upb_refcounted_isfrozen(UPB_UPCAST(def));
-}
-
-void upb_def_ref(const upb_def *def, const void *owner) {
-  upb_refcounted_ref(UPB_UPCAST(def), owner);
-}
-
-void upb_def_unref(const upb_def *def, const void *owner) {
-  upb_refcounted_unref(UPB_UPCAST(def), owner);
-}
-
-void upb_def_donateref(const upb_def *def, const void *from, const void *to) {
-  upb_refcounted_donateref(UPB_UPCAST(def), from, to);
-}
-
-void upb_def_checkref(const upb_def *def, const void *owner) {
-  upb_refcounted_checkref(UPB_UPCAST(def), owner);
-}
-
 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_UPCAST(def), vtbl, owner)) return false;
+  if (!upb_refcounted_init(upb_def_upcast_mutable(def), vtbl, owner)) return false;
   def->type = type;
   def->fullname = NULL;
   def->came_from_user = false;
@@ -131,7 +109,7 @@
 }
 
 static const char *msgdef_name(const upb_msgdef *m) {
-  const char *name = upb_def_fullname(UPB_UPCAST(m));
+  const char *name = upb_def_fullname(upb_msgdef_upcast(m));
   return name ? name : "(anonymous)";
 }
 
@@ -154,13 +132,15 @@
   }
 
   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;
     }
 
-    const upb_def *subdef = upb_fielddef_subdef(f);
+    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));
@@ -179,14 +159,14 @@
     bool has_default_name = upb_fielddef_enumhasdefaultstr(f);
     bool has_default_number = upb_fielddef_enumhasdefaultint32(f);
 
-    // Previously verified by upb_validate_enumdef().
+    /* 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).
+    /* 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) {
@@ -205,13 +185,13 @@
       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.
+    /* 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.
+  /* 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);
@@ -238,8 +218,8 @@
   return true;
 }
 
-// All submessage fields are lower than all other fields.
-// Secondly, fields are increasing in order.
+/* 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;
@@ -256,14 +236,15 @@
 }
 
 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.
+  /* 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;
 
-  upb_msg_field_iter j;
-  int i;
   m->submsg_field_count = 0;
   for(i = 0, upb_msg_field_begin(&j, m);
       !upb_msg_field_done(&j);
@@ -282,7 +263,7 @@
 
   qsort(fields, n, sizeof(*fields), cmp_fields);
 
-  uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+  selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
   for (i = 0; i < n; i++) {
     upb_fielddef *f = fields[i];
     f->index_ = i;
@@ -292,38 +273,42 @@
   m->selector_count = selector;
 
 #ifndef NDEBUG
-  // Verify that all selectors for the message are distinct.
-  //
+  {
+    /* 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);
+    if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v);
 
-  upb_inttable t;
-  upb_inttable_init(&t, UPB_CTYPE_BOOL);
-  upb_value v = upb_value_bool(true);
-  upb_selector_t sel;
-  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 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);
   }
-  upb_inttable_uninit(&t);
 #undef TRY
 #endif
 
@@ -332,14 +317,17 @@
 }
 
 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 (int i = 0; i < n; 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.
+      /* 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) {
@@ -350,14 +338,14 @@
         goto err;
       }
     } else {
-      // Set now to detect transitive closure in the second pass.
+      /* 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 (int i = 0; i < n; i++) {
+  /* 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) {
@@ -370,17 +358,17 @@
     }
   }
 
-  // Def graph contains FieldDefs between each MessageDef, so double the limit.
-  int maxdepth = UPB_MAX_MESSAGE_DEPTH * 2;
+  /* Def graph contains FieldDefs between each MessageDef, so double the
+   * limit. */
+  maxdepth = UPB_MAX_MESSAGE_DEPTH * 2;
 
-  // Validation all passed; freeze the defs.
-  bool ret =
-      upb_refcounted_freeze((upb_refcounted * const *)defs, n, s, maxdepth);
+  /* 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 (int i = 0; i < n; i++) {
+  for (i = 0; i < n; i++) {
     defs[i]->came_from_user = false;
   }
   assert(!(s && upb_ok(s)));
@@ -395,12 +383,12 @@
   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().
+    /* 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_UPCAST(e));
+  upb_def_uninit(upb_enumdef_upcast_mutable(e));
   free(e);
 }
 
@@ -408,7 +396,8 @@
   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_UPCAST(e), UPB_DEF_ENUM, &vtbl, owner)) goto err2;
+  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;
@@ -421,9 +410,9 @@
 }
 
 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;
-  upb_enum_iter i;
   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);
@@ -435,39 +424,18 @@
   return new_e;
 }
 
-bool upb_enumdef_isfrozen(const upb_enumdef *e) {
-  return upb_def_isfrozen(UPB_UPCAST(e));
-}
-
-void upb_enumdef_ref(const upb_enumdef *e, const void *owner) {
-  upb_def_ref(UPB_UPCAST(e), owner);
-}
-
-void upb_enumdef_unref(const upb_enumdef *e, const void *owner) {
-  upb_def_unref(UPB_UPCAST(e), owner);
-}
-
-void upb_enumdef_donateref(
-    const upb_enumdef *e, const void *from, const void *to) {
-  upb_def_donateref(UPB_UPCAST(e), from, to);
-}
-
-void upb_enumdef_checkref(const upb_enumdef *e, const void *owner) {
-  upb_def_checkref(UPB_UPCAST(e), owner);
-}
-
 bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) {
-  upb_def *d = UPB_UPCAST(e);
+  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_UPCAST(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_UPCAST(e), fullname, 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,
@@ -516,7 +484,7 @@
 }
 
 void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
-  // We iterate over the ntoi table, to account for duplicate numbers.
+  /* We iterate over the ntoi table, to account for duplicate numbers. */
   upb_strtable_begin(i, &e->ntoi);
 }
 
@@ -561,13 +529,13 @@
                        void *closure) {
   const upb_fielddef *f = (const upb_fielddef*)r;
   if (upb_fielddef_containingtype(f)) {
-    visit(r, UPB_UPCAST2(upb_fielddef_containingtype(f)), closure);
+    visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure);
   }
   if (upb_fielddef_containingoneof(f)) {
-    visit(r, UPB_UPCAST2(upb_fielddef_containingoneof(f)), closure);
+    visit(r, upb_oneofdef_upcast2(upb_fielddef_containingoneof(f)), closure);
   }
   if (upb_fielddef_subdef(f)) {
-    visit(r, UPB_UPCAST(upb_fielddef_subdef(f)), closure);
+    visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure);
   }
 }
 
@@ -576,26 +544,27 @@
   upb_fielddef_uninit_default(f);
   if (f->subdef_is_symbolic)
     free(f->sub.name);
-  upb_def_uninit(UPB_UPCAST(f));
+  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);
-  const upb_enumdef *e = upb_fielddef_enumsubdef(f);
+  e = upb_fielddef_enumsubdef(f);
   if (f->default_is_string && f->defaultval.bytes) {
-    // Default was explicitly set as a string.
+    /* 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.
+      /* 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.
+      /* 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);
@@ -607,21 +576,22 @@
 }
 
 static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) {
+  const upb_enumdef *e;
   assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
-  const upb_enumdef *e = upb_fielddef_enumsubdef(f);
+  e = upb_fielddef_enumsubdef(f);
   if (!f->default_is_string) {
-    // Default was explicitly set as an integer.
+    /* 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.
+      /* 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.
+      /* Default is unset; try to pull in enumdef default. */
       if (upb_enumdef_numvals(e) > 0) {
         *val = upb_enumdef_default(e);
         return true;
@@ -631,11 +601,11 @@
   return false;
 }
 
-upb_fielddef *upb_fielddef_new(const void *owner) {
+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_UPCAST(f), UPB_DEF_FIELD, &vtbl, owner)) {
+  if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD, &vtbl, o)) {
     free(f);
     return NULL;
   }
@@ -653,19 +623,20 @@
   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.
+  /* 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));
@@ -680,9 +651,8 @@
     newf->defaultval = f->defaultval;
   }
 
-  const char *srcname;
   if (f->subdef_is_symbolic) {
-    srcname = f->sub.name;  // Might be NULL.
+    srcname = f->sub.name;  /* Might be NULL. */
   } else {
     srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL;
   }
@@ -701,27 +671,6 @@
   return newf;
 }
 
-bool upb_fielddef_isfrozen(const upb_fielddef *f) {
-  return upb_def_isfrozen(UPB_UPCAST(f));
-}
-
-void upb_fielddef_ref(const upb_fielddef *f, const void *owner) {
-  upb_def_ref(UPB_UPCAST(f), owner);
-}
-
-void upb_fielddef_unref(const upb_fielddef *f, const void *owner) {
-  upb_def_unref(UPB_UPCAST(f), owner);
-}
-
-void upb_fielddef_donateref(
-    const upb_fielddef *f, const void *from, const void *to) {
-  upb_def_donateref(UPB_UPCAST(f), from, to);
-}
-
-void upb_fielddef_checkref(const upb_fielddef *f, const void *owner) {
-  upb_def_checkref(UPB_UPCAST(f), owner);
-}
-
 bool upb_fielddef_typeisset(const upb_fielddef *f) {
   return f->type_is_set_;
 }
@@ -764,7 +713,7 @@
 }
 
 const char *upb_fielddef_name(const upb_fielddef *f) {
-  return upb_def_fullname(UPB_UPCAST(f));
+  return upb_def_fullname(upb_fielddef_upcast(f));
 }
 
 const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
@@ -794,8 +743,8 @@
     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 ".").
+  /* 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;
@@ -807,7 +756,7 @@
     upb_status_seterrmsg(s, "Already added to message or oneof");
     return false;
   }
-  return upb_def_setfullname(UPB_UPCAST(f), name, s);
+  return upb_def_setfullname(upb_fielddef_upcast_mutable(f), name, s);
 }
 
 static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) {
@@ -867,7 +816,7 @@
   if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
     const char *ret = enumdefaultstr(f);
     assert(ret);
-    // Enum defaults can't have embedded NULLs.
+    /* Enum defaults can't have embedded NULLs. */
     if (len) *len = strlen(ret);
     return ret;
   }
@@ -898,7 +847,7 @@
       break;
     case UPB_TYPE_MESSAGE: break;
     case UPB_TYPE_ENUM:
-      // This is our special sentinel that indicates "not set" for an enum.
+      /* This is our special sentinel that indicates "not set" for an enum. */
       f->default_is_string = true;
       f->defaultval.bytes = NULL;
       break;
@@ -1144,6 +1093,7 @@
 
 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;
@@ -1156,7 +1106,7 @@
     assert(f->type_ == UPB_TYPE_ENUM);
   }
 
-  str_t *str2 = newstr(str, len);
+  str2 = newstr(str, len);
   f->defaultval.bytes = str2;
   f->default_is_string = true;
   return true;
@@ -1169,8 +1119,8 @@
 }
 
 bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) {
-  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
   int32_t val;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
   return enumdefaultint32(f, &val);
 }
 
@@ -1217,12 +1167,12 @@
 
 bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
                                upb_status *s) {
-  return upb_fielddef_setsubdef(f, UPB_UPCAST(subdef), 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_UPCAST(subdef), s);
+  return upb_fielddef_setsubdef(f, upb_enumdef_upcast(subdef), s);
 }
 
 bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
@@ -1232,8 +1182,8 @@
     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 ".").
+  /* 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;
@@ -1282,20 +1232,20 @@
 
 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_UPCAST2(f), closure);
+    visit(r, upb_fielddef_upcast2(f), closure);
   }
-  upb_msg_oneof_iter o;
   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_UPCAST2(f), closure);
+    visit(r, upb_oneofdef_upcast2(f), closure);
   }
 }
 
@@ -1304,7 +1254,7 @@
   upb_strtable_uninit(&m->ntoo);
   upb_strtable_uninit(&m->ntof);
   upb_inttable_uninit(&m->itof);
-  upb_def_uninit(UPB_UPCAST(m));
+  upb_def_uninit(upb_msgdef_upcast_mutable(m));
   free(m);
 }
 
@@ -1312,7 +1262,8 @@
   static const struct upb_refcounted_vtbl vtbl = {visitmsg, freemsg};
   upb_msgdef *m = malloc(sizeof(*m));
   if (!m) return NULL;
-  if (!upb_def_init(UPB_UPCAST(m), UPB_DEF_MSG, &vtbl, owner)) goto err2;
+  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;
@@ -1329,25 +1280,28 @@
 }
 
 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;
-  bool ok = upb_def_setfullname(UPB_UPCAST(newm),
-                                upb_def_fullname(UPB_UPCAST(m)), 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);
-  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_fielddef_dup(upb_msg_iter_field(&i), &f);
-    // Fields in oneofs are dup'd below.
+    /* 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;
     }
   }
-  upb_msg_oneof_iter o;
   for(upb_msg_oneof_begin(&o, m);
       !upb_msg_oneof_done(&o);
       upb_msg_oneof_next(&o)) {
@@ -1360,43 +1314,22 @@
   return newm;
 }
 
-bool upb_msgdef_isfrozen(const upb_msgdef *m) {
-  return upb_def_isfrozen(UPB_UPCAST(m));
-}
-
-void upb_msgdef_ref(const upb_msgdef *m, const void *owner) {
-  upb_def_ref(UPB_UPCAST(m), owner);
-}
-
-void upb_msgdef_unref(const upb_msgdef *m, const void *owner) {
-  upb_def_unref(UPB_UPCAST(m), owner);
-}
-
-void upb_msgdef_donateref(
-    const upb_msgdef *m, const void *from, const void *to) {
-  upb_def_donateref(UPB_UPCAST(m), from, to);
-}
-
-void upb_msgdef_checkref(const upb_msgdef *m, const void *owner) {
-  upb_def_checkref(UPB_UPCAST(m), owner);
-}
-
 bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) {
-  upb_def *d = UPB_UPCAST(m);
+  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_UPCAST(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_UPCAST(m), fullname, 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.
+/* 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) {
@@ -1426,40 +1359,42 @@
 
 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.
+  /* 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.
+  /* 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.
+    /* 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.
+  /* 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) {
-  // Check various conditions that would prevent this oneof from being added.
+  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;
@@ -1471,9 +1406,8 @@
     return false;
   }
 
-  // Check that all of the oneof's fields do not conflict with names or numbers
-  // of fields already in the message.
-  upb_oneof_iter it;
+  /* 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)) {
@@ -1481,15 +1415,15 @@
     }
   }
 
-  // Everything checks out -- commit now.
+  /* Everything checks out -- commit now. */
 
-  // Add oneof itself first.
+  /* 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.
+  /* 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);
@@ -1581,10 +1515,10 @@
   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_UPCAST2(f), closure);
+    visit(r, upb_fielddef_upcast2(f), closure);
   }
   if (o->parent) {
-    visit(r, UPB_UPCAST2(o->parent), closure);
+    visit(r, upb_msgdef_upcast2(o->parent), closure);
   }
 }
 
@@ -1592,7 +1526,7 @@
   upb_oneofdef *o = (upb_oneofdef*)r;
   upb_strtable_uninit(&o->ntof);
   upb_inttable_uninit(&o->itof);
-  upb_def_uninit(UPB_UPCAST(o));
+  upb_def_uninit(upb_oneofdef_upcast_mutable(o));
   free(o);
 }
 
@@ -1601,7 +1535,9 @@
   upb_oneofdef *o = malloc(sizeof(*o));
   o->parent = NULL;
   if (!o) return NULL;
-  if (!upb_def_init(UPB_UPCAST(o), UPB_DEF_ONEOF, &vtbl, owner)) goto err2;
+  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;
@@ -1614,12 +1550,13 @@
 }
 
 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;
-  bool ok = upb_def_setfullname(UPB_UPCAST(newo),
-                                upb_def_fullname(UPB_UPCAST(o)), NULL);
+  ok = upb_def_setfullname(upb_oneofdef_upcast_mutable(newo),
+                           upb_def_fullname(upb_oneofdef_upcast(o)), NULL);
   UPB_ASSERT_VAR(ok, ok);
-  upb_oneof_iter i;
   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)) {
@@ -1630,29 +1567,8 @@
   return newo;
 }
 
-bool upb_oneofdef_isfrozen(const upb_oneofdef *o) {
-  return upb_def_isfrozen(UPB_UPCAST(o));
-}
-
-void upb_oneofdef_ref(const upb_oneofdef *o, const void *owner) {
-  upb_def_ref(UPB_UPCAST(o), owner);
-}
-
-void upb_oneofdef_unref(const upb_oneofdef *o, const void *owner) {
-  upb_def_unref(UPB_UPCAST(o), owner);
-}
-
-void upb_oneofdef_donateref(const upb_oneofdef *o, const void *from,
-                           const void *to) {
-  upb_def_donateref(UPB_UPCAST(o), from, to);
-}
-
-void upb_oneofdef_checkref(const upb_oneofdef *o, const void *owner) {
-  upb_def_checkref(UPB_UPCAST(o), owner);
-}
-
 const char *upb_oneofdef_name(const upb_oneofdef *o) {
-  return upb_def_fullname(UPB_UPCAST(o));
+  return upb_def_fullname(upb_oneofdef_upcast(o));
 }
 
 bool upb_oneofdef_setname(upb_oneofdef *o, const char *fullname,
@@ -1661,7 +1577,7 @@
     upb_status_seterrmsg(s, "oneof already added to a message");
     return false;
   }
-  return upb_def_setfullname(UPB_UPCAST(o), fullname, s);
+  return upb_def_setfullname(upb_oneofdef_upcast_mutable(o), fullname, s);
 }
 
 const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
@@ -1678,20 +1594,20 @@
   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.
+  /* 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.
+  /* 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.
+  /* 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;
@@ -1704,21 +1620,21 @@
     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.
+  /* 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 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 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 "
@@ -1727,8 +1643,8 @@
     }
   }
 
-  // Commit phase. First add the field to our parent msgdef, if any, because
-  // that may fail; then add the field to our own tables.
+  /* 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)) {
@@ -1779,23 +1695,291 @@
 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;
+}
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * TODO(haberman): it's unclear whether a lot of the consistency checks should
- * assert() or return false.
- */
+** 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.
+
+/* Defined for the sole purpose of having a unique pointer value for
+ * UPB_NO_CLOSURE. */
 char _upb_noclosure;
 
 static void freehandlers(upb_refcounted *r) {
@@ -1824,42 +2008,45 @@
       !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;
-    const upb_handlers *sub = upb_handlers_getsubhandlers(h, f);
-    if (sub) visit(r, UPB_UPCAST(sub), closure);
+    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_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.
+/* 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.
-  upb_msg_field_iter i;
+  /* 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;
 
-    const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
-    upb_value subm_ent;
+    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 {
@@ -1876,11 +2063,11 @@
   return NULL;
 }
 
-// Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
-// subhandlers for this submessage field.
+/* 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.
+/* 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,
@@ -1918,6 +2105,10 @@
 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) {
@@ -1932,15 +2123,13 @@
     return false;
   }
 
-  upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
   if (attr) {
     set_attr = *attr;
   }
 
-  // Check that the given closure type matches the closure type that has been
-  // established for this context (if any).
-  const void *closure_type = upb_handlerattr_closuretype(&set_attr);
-  const void **context_closure_type;
+  /* 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);
@@ -1954,16 +2143,23 @@
 
   if (closure_type && *context_closure_type &&
       closure_type != *context_closure_type) {
-    // TODO(haberman): better message for debugging.
-    upb_status_seterrmsg(&h->status_, "closure type does not match");
+    /* 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 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 =
@@ -1982,17 +2178,20 @@
   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).
+/* 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) {
-  assert(type != UPB_HANDLER_STRING);
-  const void *ret = h->top_closure_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 &&
@@ -2005,26 +2204,30 @@
     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);
-  // }
+  /* 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.
+/* 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;
-  const void *closure_type = effective_closure_type(h, f, type);
-  const upb_handlerattr *attr = &h->table[sel].attr;
-  const void *return_closure_type = upb_handlerattr_returnclosuretype(attr);
+  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,
@@ -2037,32 +2240,14 @@
 
 /* Public interface ***********************************************************/
 
-bool upb_handlers_isfrozen(const upb_handlers *h) {
-  return upb_refcounted_isfrozen(UPB_UPCAST(h));
-}
-
-void upb_handlers_ref(const upb_handlers *h, const void *owner) {
-  upb_refcounted_ref(UPB_UPCAST(h), owner);
-}
-
-void upb_handlers_unref(const upb_handlers *h, const void *owner) {
-  upb_refcounted_unref(UPB_UPCAST(h), owner);
-}
-
-void upb_handlers_donateref(
-    const upb_handlers *h, const void *from, const void *to) {
-  upb_refcounted_donateref(UPB_UPCAST(h), from, to);
-}
-
-void upb_handlers_checkref(const upb_handlers *h, const void *owner) {
-  upb_refcounted_checkref(UPB_UPCAST(h), owner);
-}
-
 upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
+  int extra;
+  upb_handlers *h;
+
   assert(upb_msgdef_isfrozen(md));
 
-  int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
-  upb_handlers *h = calloc(sizeof(*h) + extra, 1);
+  extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
+  h = calloc(sizeof(*h) + extra, 1);
   if (!h) return NULL;
 
   h->msg = md;
@@ -2070,14 +2255,15 @@
   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_UPCAST(h), &vtbl, owner)) 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.
+  /* calloc() above initialized all handlers to NULL. */
   return h;
 
 oom:
-  freehandlers(UPB_UPCAST(h));
+  freehandlers(upb_handlers_upcast_mutable(h));
   return NULL;
 }
 
@@ -2086,17 +2272,21 @@
                                            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;
 
-  upb_handlers *ret = newformsg(m, owner, &state);
+  ret = newformsg(m, owner, &state);
 
   upb_inttable_uninit(&state.tab);
   if (!ret) return NULL;
 
-  upb_refcounted *r = UPB_UPCAST(ret);
-  bool ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH);
+  r = upb_handlers_upcast_mutable(ret);
+  ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH);
   UPB_ASSERT_VAR(ok, ok);
 
   return ret;
@@ -2119,20 +2309,20 @@
     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);
+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
 
@@ -2154,8 +2344,8 @@
   assert(sub);
   assert(!upb_handlers_isfrozen(h));
   assert(upb_fielddef_issubmsg(f));
-  if (SUBH_F(h, f)) return false;  // Can't reset.
-  if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(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;
@@ -2179,17 +2369,18 @@
 
 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.
+  /* 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;
   }
-  bool ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func));
+  ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func));
   UPB_ASSERT_VAR(ok, ok);
   return true;
 }
@@ -2198,8 +2389,10 @@
 /* "Static" methods ***********************************************************/
 
 bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
-  // TODO: verify we have a transitive closure.
-  for (int i = 0; i < n; i++) {
+  /* 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_)) {
@@ -2209,9 +2402,8 @@
       return false;
     }
 
-    // Check that there are no closure mismatches due to missing Start* handlers
-    // or subhandlers with different type-level types.
-    upb_msg_field_iter j;
+    /* 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)) {
@@ -2245,29 +2437,29 @@
         }
 
         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.
+          /* 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.
+        /* TODO(haberman): check type of submessage.
+         * This is slightly tricky; also consider whether we should check that
+         * they match at setsubhandlers time. */
       }
     }
   }
@@ -2290,7 +2482,7 @@
     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.
+    default: assert(false); return -1;  /* Invalid input. */
   }
 }
 
@@ -2342,10 +2534,10 @@
       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.
+      /* 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:
@@ -2353,7 +2545,7 @@
       *s = f->selector_base;
       break;
   }
-  assert(*s < upb_fielddef_containingtype(f)->selector_count);
+  assert((size_t)*s < upb_fielddef_containingtype(f)->selector_count);
   return true;
 }
 
@@ -2363,13 +2555,13 @@
 
 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_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)
+    /* ENDSUBMSG (STARTSUBMSG is at table beginning) */
     ret += 0;
     if (upb_fielddef_lazy(f)) {
-      // STARTSTR/ENDSTR/STRING (for lazy)
+      /* STARTSTR/ENDSTR/STRING (for lazy) */
       ret += 3;
     }
   }
@@ -2433,7 +2625,7 @@
   memset(h, 0, sizeof(*h));
 }
 
-// For when we support handlerfree callbacks.
+/* For when we support handlerfree callbacks. */
 void upb_byteshandler_uninit(upb_byteshandler* h) {
   UPB_UNUSED(h);
 }
@@ -2459,24 +2651,21 @@
   return true;
 }
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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>
@@ -2489,17 +2678,17 @@
 
 /* arch-specific atomic primitives  *******************************************/
 
-#ifdef UPB_THREAD_UNSAFE  //////////////////////////////////////////////////////
+#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__) //////////////////////////////////
+#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) ///////////////////////////////////////////////////////////
+#elif defined(WIN32) /*-------------------------------------------------------*/
 
 #include <Windows.h>
 
@@ -2513,13 +2702,13 @@
        Implement them or compile with UPB_THREAD_UNSAFE.
 #endif
 
-// All static objects point to this refcount.
-// It is special-cased in ref/unref below.
+/* 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.
+/* 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)
@@ -2546,21 +2735,21 @@
 
 #else
 
-// User must define functions that lock/unlock a global mutex and link this
-// file against them.
+/* 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.
+/* 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).
+  int count;  /* How many refs there are (duplicates only allowed for ref2). */
   bool is_ref2;
 } trackedref;
 
@@ -2573,18 +2762,19 @@
 }
 
 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();
-  upb_value v;
   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.
+    /* 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++;
@@ -2593,8 +2783,8 @@
     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.
+      /* 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));
@@ -2605,22 +2795,25 @@
 }
 
 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();
-  upb_value v;
-  bool found = upb_inttable_lookupptr(r->refs, owner, &v);
-  // This assert will fail if an owner attempts to release a ref it didn't have.
+  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);
-  trackedref *ref = upb_value_getptr(v);
+  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.
+      /* 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);
@@ -2630,32 +2823,41 @@
 }
 
 static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
-  upb_lock();
   upb_value v;
-  bool found = upb_inttable_lookupptr(r->refs, owner, &v);
+  bool found;
+  trackedref *ref;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
   UPB_ASSERT_VAR(found, found);
-  trackedref *ref = upb_value_getptr(v);
+  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.
+/* 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_lock();
   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.
-    upb_value v;
-    bool found = upb_inttable_lookupptr(to->refs, owner, &v);
+    /* To get the count we need to look in the target's table. */
+    found = upb_inttable_lookupptr(to->refs, owner, &v);
     assert(found);
-    trackedref *ref = upb_value_getptr(v);
-    upb_value count = upb_value_int32(ref->count);
+    ref = upb_value_getptr(v);
+    count = upb_value_int32(ref->count);
 
-    bool ok = upb_inttable_insertptr(tab, to, count);
+    ok = upb_inttable_insertptr(tab, to, count);
     CHECK_OOM(ok);
   }
   upb_unlock();
@@ -2669,15 +2871,18 @@
 static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj,
                         void *closure) {
   check_state *s = closure;
-  assert(obj == s->obj);
-  assert(subobj);
   upb_inttable *ref2 = &s->ref2;
   upb_value v;
-  bool 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.
+  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);
-  int32_t newcount = upb_value_getint32(v) - 1;
+  newcount = upb_value_getint32(v) - 1;
   if (newcount > 0) {
     upb_inttable_insert(ref2, (uintptr_t)subobj, upb_value_int32(newcount));
   }
@@ -2685,19 +2890,21 @@
 
 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.
+  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;
-  bool ok = upb_inttable_init(&state.ref2, UPB_CTYPE_INT32);
+  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.
+  /* 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.
+  /* 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);
@@ -2761,27 +2968,27 @@
   if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
 }
 
-#endif  // UPB_DEBUG_REFS
+#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 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).
+/* 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.
+  /* 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_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;
@@ -2790,15 +2997,15 @@
                          const upb_refcounted *subobj,
                          void *closure);
 
-// Node attributes /////////////////////////////////////////////////////////////
+/* Node attributes -----------------------------------------------------------*/
 
-// After our analysis phase all nodes will be either GRAY or WHITE.
+/* 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).
+  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); }
@@ -2826,7 +3033,7 @@
 }
 
 static color_t color(tarjan *t, const upb_refcounted *r) {
-  return trygetattr(t, r) & 0x3;  // Color is always stored in the low 2 bits.
+  return trygetattr(t, r) & 0x3;  /* Color is always stored in the low 2 bits. */
 }
 
 static void set_gray(tarjan *t, const upb_refcounted *r) {
@@ -2834,11 +3041,11 @@
   setattr(t, r, GRAY);
 }
 
-// Pushes an obj onto the Tarjan stack and sets it to GREEN.
+/* 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).
+  /* 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");
@@ -2847,13 +3054,13 @@
   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.
+/* 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.
+  /* 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;
 }
@@ -2861,7 +3068,7 @@
 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).
+  /* 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);
@@ -2889,21 +3096,27 @@
 }
 
 static uint32_t *group(tarjan *t, upb_refcounted *r) {
-  assert(color(t, r) == WHITE);
-  uint64_t groupnum = getattr(t, r) >> 8;
+  uint64_t groupnum;
   upb_value v;
-  bool found = upb_inttable_lookup(&t->groups, groupnum, &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.
+/* 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) {
-  assert(color(t, r) == WHITE);
-  uint64_t leader_slot = (getattr(t, r) >> 8) + 1;
+  uint64_t leader_slot;
   upb_value v;
-  bool found = upb_inttable_lookup(&t->groups, leader_slot, &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);
@@ -2915,10 +3128,10 @@
 }
 
 
-// Tarjan's algorithm //////////////////////////////////////////////////////////
+/* Tarjan's algorithm --------------------------------------------------------*/
 
-// See:
-//   http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_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,
@@ -2929,14 +3142,14 @@
     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.
+    /* 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.
+    /* 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.
+    /* 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;
@@ -2944,7 +3157,7 @@
 
 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.
+    /* 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);
   }
@@ -2959,15 +3172,15 @@
 }
 
 
-// freeze() ////////////////////////////////////////////////////////////////////
+/* 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.
+    /* 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);
   }
 }
@@ -2975,10 +3188,12 @@
 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.
+  /* 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;
@@ -2990,64 +3205,65 @@
   if (setjmp(t.err) != 0) goto err4;
 
 
-  for (int i = 0; i < n; i++) {
+  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.
+  /* 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))
+  /* 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_iter i;
-  upb_inttable_begin(&i, &t.objattr);
-  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
-    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i);
-    // 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.
+  /* 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) {
-      // Remove from old group.
+      upb_refcounted *leader;
+
+      /* Remove from old group. */
       upb_refcounted *move = obj->next;
       if (obj == move) {
-        // Removing the last object from a group.
+        /* 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.
+        /* 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.
-      upb_refcounted *leader = groupleader(&t, move);
+      /* Add to new group. */
+      leader = groupleader(&t, move);
       if (move == leader) {
-        // First object added to new group is its 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.
+        /* Group already has at least one object in it. */
         assert(leader->group == group(&t, move));
         move->group = group(&t, move);
         move->next = leader->next;
@@ -3059,40 +3275,42 @@
     }
   }
 
-  // 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(&i, &t.objattr);
-  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
-    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i);
+  /* 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(&i, &t.objattr);
-  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
-    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i);
+  /* 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) {
-        // 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_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()).
-        upb_refcounted *o = obj;
+        /* 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.
+        /* 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);
       }
@@ -3102,9 +3320,9 @@
 
 err4:
   if (!ret) {
-    upb_inttable_begin(&i, &t.groups);
-    for(; !upb_inttable_done(&i); upb_inttable_next(&i))
-      free(upb_value_getptr(upb_inttable_iter_value(&i)));
+    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:
@@ -3123,21 +3341,24 @@
 }
 
 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);
-  upb_refcounted *base = from;
+  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
+  /* 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.
-  upb_refcounted *tmp = r->next;
+  /* Merge the two circularly linked lists by swapping their next pointers. */
+  tmp = r->next;
   r->next = base->next;
   base->next = tmp;
 }
@@ -3157,11 +3378,13 @@
 
 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.
-    const upb_refcounted *o = r;
+    /* 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;
@@ -3185,6 +3408,18 @@
 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;
@@ -3219,7 +3454,7 @@
 }
 
 void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) {
-  assert(!from->is_frozen);  // Non-const pointer implies this.
+  assert(!from->is_frozen);  /* Non-const pointer implies this. */
   track(r, from, true);
   if (r->is_frozen) {
     refgroup(r->group);
@@ -3229,7 +3464,7 @@
 }
 
 void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) {
-  assert(!from->is_frozen);  // Non-const pointer implies this.
+  assert(!from->is_frozen);  /* Non-const pointer implies this. */
   untrack(r, from, true);
   if (r->is_frozen) {
     unref(r);
@@ -3253,22 +3488,17 @@
 
 bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
                            int maxdepth) {
-  for (int i = 0; i < n; i++) {
+  int i;
+  for (i = 0; i < n; i++) {
     assert(!roots[i]->is_frozen);
   }
   return freeze(roots, n, s, maxdepth);
 }
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2013 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
 
 
 #include <stdlib.h>
 
-// Fallback implementation if the shim is not specialized by the JIT.
+/* 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;                                                           \
@@ -3290,12 +3520,14 @@
 
 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 attr = UPB_HANDLERATTR_INITIALIZER;
   upb_handlerattr_sethandlerdata(&attr, d);
   upb_handlerattr_setalwaysok(&attr, true);
   upb_handlers_addcleanup(h, d, free);
@@ -3304,7 +3536,7 @@
   case UPB_TYPE_##u: \
     ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
 
-  bool ok = false;
+  ok = false;
 
   switch (upb_fielddef_type(f)) {
     TYPE(INT64,  int64);
@@ -3347,38 +3579,11 @@
 
   return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s);
 }
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2008-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
 
 
 #include <stdlib.h>
 #include <string.h>
 
-bool upb_symtab_isfrozen(const upb_symtab *s) {
-  return upb_refcounted_isfrozen(UPB_UPCAST(s));
-}
-
-void upb_symtab_ref(const upb_symtab *s, const void *owner) {
-  upb_refcounted_ref(UPB_UPCAST(s), owner);
-}
-
-void upb_symtab_unref(const upb_symtab *s, const void *owner) {
-  upb_refcounted_unref(UPB_UPCAST(s), owner);
-}
-
-void upb_symtab_donateref(
-    const upb_symtab *s, const void *from, const void *to) {
-  upb_refcounted_donateref(UPB_UPCAST(s), from, to);
-}
-
-void upb_symtab_checkref(const upb_symtab *s, const void *owner) {
-  upb_refcounted_checkref(UPB_UPCAST(s), owner);
-}
-
 static void upb_symtab_free(upb_refcounted *r) {
   upb_symtab *s = (upb_symtab*)r;
   upb_strtable_iter i;
@@ -3395,18 +3600,21 @@
 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_UPCAST(s), &vtbl, owner);
+  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));
-  upb_refcounted *r = UPB_UPCAST(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.
-  bool ok = upb_refcounted_freeze(&r, 1, NULL, 0);
+  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);
 }
 
@@ -3431,19 +3639,19 @@
   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.
+/* 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 '.'
+    /* 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.
+    /* 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;
@@ -3456,57 +3664,95 @@
   return ret;
 }
 
-// Searches def and its children to find defs that have the same name as any
-// def in "addtab."  Returns true if any where found, and as a side-effect adds
-// duplicates of these defs into addtab.
-//
-// We use a modified depth-first traversal that traverses each SCC (which we
-// already computed) as if it were a single node.  This allows us to traverse
-// the possibly-cyclic graph as if it were a DAG and to dup the correct set of
-// nodes with O(n) time.
+/* 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) {
-  // Memoize results of this function for efficiency (since we're traversing a
-  // DAG this is not needed to limit the depth of the search).
   upb_value v;
-  if (upb_inttable_lookup(seen, (uintptr_t)def, &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.
-  bool need_dup = false;
-  const upb_def *base = def;
+  /* 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;
-    upb_value v;
     if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) {
       need_dup = true;
     }
 
-    // For messages, continue the recursion by visiting all subdefs.
-    const upb_msgdef *m = upb_dyncast_msgdef(def);
+    /* 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;
-        // |= to avoid short-circuit; we need its side-effects.
-        need_dup |= upb_resolve_dfs(
-            upb_fielddef_subdef(f), addtab, new_owner, seen, s);
+        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 any defs that don't already have entries in addtab.
+    /* 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;
-      const char *name = upb_def_fullname(def);
+      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;
@@ -3517,7 +3763,7 @@
     } while ((def = (upb_def*)def->base.next) != base);
   }
 
-  upb_inttable_insert(seen, (uintptr_t)def, upb_value_bool(need_dup));
+  upb_inttable_insertptr(seen, memoize_key, upb_value_bool(need_dup));
   return need_dup;
 
 oom:
@@ -3525,34 +3771,41 @@
   return false;
 }
 
-// TODO(haberman): we need a lot more testing of error conditions.
-// The came_from_user stuff in particular is not tested.
+/* 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) {
-  assert(!upb_symtab_isfrozen(s));
+  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 (int i = 0; i < n; i++) {
+  /* 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));
-    const char *fullname = upb_def_fullname(def);
+    fullname = upb_def_fullname(def);
     if (!fullname) {
       upb_status_seterrmsg(
           status, "Anonymous defs cannot be added to a symtab");
       goto err;
     }
 
-    upb_fielddef *f = upb_dyncast_fielddef_mutable(def);
+    f = upb_dyncast_fielddef_mutable(def);
 
     if (f) {
       if (!upb_fielddef_containingtypename(f)) {
@@ -3566,8 +3819,8 @@
         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.
+      /* 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)))
@@ -3575,31 +3828,33 @@
     }
   }
 
-  // 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 (int i = 0; i < n; i++) {
+  /* 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;
-    const char *msgname = upb_fielddef_containingtypename(f);
-    // We validated this earlier in this function.
+    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 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++;
     }
 
-    upb_value v;
-    upb_msgdef *m;
     if (upb_strtable_lookup(&addtab, msgname, &v)) {
-      // Extendee is in the set of defs the user asked us to add.
+      /* 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.
+      /* 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,
@@ -3621,37 +3876,37 @@
     }
   }
 
-  // Add dups of any existing def that can reach a def with the same name as
-  // anything in our "add" set.
-  upb_inttable seen;
+  /* 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_iter i;
-  upb_strtable_begin(&i, &s->symtab);
-  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
-    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+  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(&i, &addtab);
-  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
-    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+  /* 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);
-    if (!m) continue;
-    // Type names are resolved relative to the message in which they appear.
-    const char *base = upb_msgdef_fullname(m);
-
     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.
+        /* 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);
@@ -3667,31 +3922,33 @@
     }
   }
 
-  // We need an array of the defs in addtab, for passing to upb_def_freeze.
+  /* 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(&i, &addtab);
-  for (n = 0; !upb_strtable_done(&i); upb_strtable_next(&i)) {
-    add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&i));
+  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.
+  /* 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 (int i = 0; i < n; i++) {
+  /* 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);
     }
-    bool success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
+    success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
     UPB_ASSERT_VAR(success, success == true);
   }
   free(add_defs);
@@ -3700,12 +3957,11 @@
 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_iter i;
-    upb_strtable_begin(&i, &addtab);
-    for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
-      upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+    /* 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) {
@@ -3721,7 +3977,7 @@
   return false;
 }
 
-// Iteration.
+/* Iteration. */
 
 static void advance_to_matching(upb_symtab_iter *iter) {
   if (iter->type == UPB_DEF_ANY)
@@ -3753,29 +4009,26 @@
   return upb_value_getptr(upb_strtable_iter_value(&iter->iter));
 }
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * Implementation is heavily inspired by Lua's ltable.c.
- */
+** upb_table Implementation
+**
+** Implementation is heavily inspired by Lua's ltable.c.
+*/
 
 
 #include <stdlib.h>
 #include <string.h>
 
-#define UPB_MAXARRSIZE 16  // 64k.
+#define UPB_MAXARRSIZE 16  /* 64k. */
 
-// From Chromium.
+/* 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.
+/* 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; }
@@ -3784,7 +4037,7 @@
   int ret = 0;
   bool pow2 = is_pow2(v);
   while (v >>= 1) ret++;
-  ret = pow2 ? ret : ret + 1;  // Ceiling.
+  ret = pow2 ? ret : ret + 1;  /* Ceiling. */
   return UPB_MIN(UPB_MAXARRSIZE, ret);
 }
 
@@ -3793,12 +4046,15 @@
 }
 
 char *upb_strdup2(const char *s, size_t len) {
-  // Prevent overflow errors.
+  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.
-  size_t n = len + 1;
-  char *p = malloc(n);
+  /* 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;
@@ -3806,21 +4062,25 @@
   return p;
 }
 
-// A type to represent the lookup key of either a strtable or an inttable.
-typedef struct {
-  upb_tabkey key;
+/* 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.key.s.str = (char*)str;
-  k.key.s.length = len;
+  k.str.str = str;
+  k.str.len = len;
   return k;
 }
 
 static lookupkey_t intkey(uintptr_t key) {
   lookupkey_t k;
-  k.key = upb_intkey(key);
+  k.num = key;
   return k;
 }
 
@@ -3829,7 +4089,7 @@
 
 /* Base table (shared code) ***************************************************/
 
-// For when we need to cast away const.
+/* For when we need to cast away const. */
 static upb_tabent *mutable_entries(upb_table *t) {
   return (upb_tabent*)t->entries;
 }
@@ -3839,11 +4099,13 @@
 }
 
 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;
-  size_t bytes = upb_table_size(t) * sizeof(upb_tabent);
+  bytes = upb_table_size(t) * sizeof(upb_tabent);
   if (bytes > 0) {
     t->entries = malloc(bytes);
     if (!t->entries) return false;
@@ -3867,8 +4129,10 @@
 
 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;
-  const upb_tabent *e = upb_getentry(t, hash);
+  e = upb_getentry(t, hash);
   if (upb_tabent_isempty(e)) return NULL;
   while (1) {
     if (eql(e->key, key)) return e;
@@ -3886,7 +4150,7 @@
   const upb_tabent *e = findentry(t, key, hash, eql);
   if (e) {
     if (v) {
-      _upb_value_setval(v, e->val, t->ctype);
+      _upb_value_setval(v, e->val.val, t->ctype);
     }
     return true;
   } else {
@@ -3894,34 +4158,41 @@
   }
 }
 
-// The given key must not already exist in the table.
-static void insert(upb_table *t, lookupkey_t key, upb_value val,
-                   uint32_t hash, hashfunc_t *hashfunc, eqlfunc_t *eql) {
+/* 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++;
-  upb_tabent *mainpos_e = getentry_mutable(t, hash);
-  upb_tabent *our_e = mainpos_e;
+  mainpos_e = getentry_mutable(t, hash);
+  our_e = mainpos_e;
+
   if (upb_tabent_isempty(mainpos_e)) {
-    // Our main position is empty; use it.
+    /* Our main position is empty; use it. */
     our_e->next = NULL;
   } else {
-    // Collision.
+    /* Collision. */
     upb_tabent *new_e = emptyent(t);
-    // Head of collider's chain.
+    /* 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.
+      /* 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.
+      /* 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);
@@ -3931,8 +4202,8 @@
       our_e->next = NULL;
     }
   }
-  our_e->key = key.key;
-  our_e->val = val.val;
+  our_e->key = tabkey;
+  our_e->val.val = val.val;
   assert(findentry(t, key, hash, eql) == our_e);
 }
 
@@ -3941,33 +4212,36 @@
   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.
+    /* Element to remove is at the head of its chain. */
     t->count--;
     if (val) {
-      _upb_value_setval(val, chain->val, t->ctype);
+      _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.num = 0;  // Make the slot empty.
+      move->key = 0;  /* Make the slot empty. */
     } else {
       if (removed) *removed = chain->key;
-      chain->key.num = 0;  // Make the slot empty.
+      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.
+    /* 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.
+      /* Found element to remove. */
+      upb_tabent *rm;
+
       if (val) {
-        _upb_value_setval(val, chain->next->val, t->ctype);
+        _upb_value_setval(val, chain->next->val.val, t->ctype);
       }
-      upb_tabent *rm = (upb_tabent*)chain->next;
+      rm = (upb_tabent*)chain->next;
       if (removed) *removed = rm->key;
-      rm->key.num = 0;
+      rm->key = 0;
       chain->next = rm->next;
       t->count--;
       return true;
@@ -3993,15 +4267,26 @@
 
 /* upb_strtable ***************************************************************/
 
-// A simple "subclass" of upb_table that only adds a hash function for strings.
+/* 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) {
-  return MurmurHash2(key.s.str, key.s.length, 0);
+  uint32_t len;
+  char *str = upb_tabstr(key, &len);
+  return MurmurHash2(str, len, 0);
 }
 
 static bool streql(upb_tabkey k1, lookupkey_t k2) {
-  return k1.s.length == k2.key.s.length &&
-         memcmp(k1.s.str, k2.key.s.str, k1.s.length) == 0;
+  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) {
@@ -4009,16 +4294,18 @@
 }
 
 void upb_strtable_uninit(upb_strtable *t) {
-  for (size_t i = 0; i < upb_table_size(&t->t); i++)
-    free((void*)t->t.entries[i].key.s.str);
+  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_iter i;
   upb_strtable_begin(&i, t);
   for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
     upb_strtable_insert2(
@@ -4034,17 +4321,23 @@
 
 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.
+    /* 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;
     }
   }
-  if ((k = upb_strdup2(k, len)) == NULL) return false;
 
-  lookupkey_t key = strkey2(k, len);
-  uint32_t hash = MurmurHash2(key.key.s.str, key.key.s.length, 0);
-  insert(&t->t, key, v, hash, &strhash, &streql);
+  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;
 }
 
@@ -4059,14 +4352,14 @@
   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.s.str);
+    free((void*)tabkey);
     return true;
   } else {
     return false;
   }
 }
 
-// Iteration
+/* Iteration */
 
 static const upb_tabent *str_tabent(const upb_strtable_iter *i) {
   return &i->t->t.entries[i->index];
@@ -4088,17 +4381,19 @@
 
 const char *upb_strtable_iter_key(upb_strtable_iter *i) {
   assert(!upb_strtable_done(i));
-  return str_tabent(i)->key.s.str;
+  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));
-  return str_tabent(i)->key.s.length;
+  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, i->t->t.ctype);
+  return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype);
 }
 
 void upb_strtable_iter_setdone(upb_strtable_iter *i) {
@@ -4115,20 +4410,20 @@
 
 /* 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.
+/* 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.num); }
+static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
 
 static bool inteql(upb_tabkey k1, lookupkey_t k2) {
-  return k1.num == k2.key.num;
+  return k1 == k2.num;
 }
 
-static _upb_value *mutable_array(upb_inttable *t) {
-  return (_upb_value*)t->array;
+static upb_tabval *mutable_array(upb_inttable *t) {
+  return (upb_tabval*)t->array;
 }
 
-static _upb_value *inttable_val(upb_inttable *t, uintptr_t key) {
+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 {
@@ -4138,7 +4433,7 @@
   }
 }
 
-static const _upb_value *inttable_val_const(const upb_inttable *t,
+static const upb_tabval *inttable_val_const(const upb_inttable *t,
                                             uintptr_t key) {
   return inttable_val((upb_inttable*)t, key);
 }
@@ -4150,25 +4445,29 @@
 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));
+  {
+    /* 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));
   }
-  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.
+  /* 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;
-  size_t array_bytes = t->array_size * sizeof(upb_value);
+  array_bytes = t->array_size * sizeof(upb_value);
   t->array = malloc(array_bytes);
   if (!t->array) {
     uninit(&t->t);
@@ -4189,24 +4488,32 @@
 }
 
 bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) {
-  assert(upb_arrhas(val.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;
+    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.
+      /* 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;
-      size_t i;
       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, t->t.ctype);
-        uint32_t hash = upb_inthash(e->key.num);
-        insert(&new_table, intkey(e->key.num), v, hash, &inthash, &inteql);
+
+        _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);
@@ -4214,23 +4521,23 @@
       uninit(&t->t);
       t->t = new_table;
     }
-    insert(&t->t, intkey(key), val, upb_inthash(key), &inthash, &inteql);
+    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_value *table_v = inttable_val_const(t, key);
+  const upb_tabval *table_v = inttable_val_const(t, key);
   if (!table_v) return false;
-  if (v) _upb_value_setval(v, *table_v, t->t.ctype);
+  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_value *table_v = inttable_val(t, key);
+  upb_tabval *table_v = inttable_val(t, key);
   if (!table_v) return false;
-  *table_v = val.val;
+  table_v->val = val.val;
   return true;
 }
 
@@ -4238,11 +4545,11 @@
   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], t->t.ctype);
+        _upb_value_setval(val, t->array[key].val, t->t.ctype);
       }
-      _upb_value empty = UPB_ARRAY_EMPTYENT;
       mutable_array(t)[key] = empty;
       success = true;
     } else {
@@ -4282,10 +4589,14 @@
 }
 
 void upb_inttable_compact(upb_inttable *t) {
-  // Create a power-of-two histogram of the table keys.
+  /* 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);
@@ -4295,15 +4606,17 @@
     counts[log2ceil(key)]++;
   }
 
-  int arr_size;
-  int arr_count = upb_inttable_count(t);
+  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.
+    /* 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.
-    for (int size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 1; size_lg2--) {
+    /* 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) {
@@ -4312,38 +4625,39 @@
     }
   }
 
-  // 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.
+  /* 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);
+  {
+    /* 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);
 
-  upb_inttable new_t;
-  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(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);
   }
-  assert(new_t.array_size == arr_size);
-  assert(new_t.t.size_lg2 == hashsize_lg2);
   upb_inttable_uninit(t);
   *t = new_t;
 }
 
-// Iteration.
+/* 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_value int_arrent(const upb_inttable_iter *i) {
+static upb_tabval int_arrent(const upb_inttable_iter *i) {
   assert(i->array_part);
   return i->t->array[i->index];
 }
@@ -4382,13 +4696,13 @@
 
 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.num;
+  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] : int_tabent(i)->val,
+      i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val,
       i->t->t.ctype);
 }
 
@@ -4406,26 +4720,26 @@
 }
 
 #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.
+/* -----------------------------------------------------------------------------
+ * 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.
+  /* '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
+  /* Initialize the hash to a 'random' value */
   uint32_t h = seed ^ len;
 
-  // Mix 4 bytes at a time into the hash
+  /* 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;
@@ -4441,15 +4755,15 @@
     len -= 4;
   }
 
-  // Handle the last few bytes of the input array
+  /* 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.
+  /* 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;
@@ -4457,13 +4771,13 @@
   return h;
 }
 
-#else // !UPB_UNALIGNED_READS_OK
+#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
+/* -----------------------------------------------------------------------------
+ * 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; }
 
@@ -4475,8 +4789,10 @@
   uint8_t align = (uintptr_t)data & 3;
 
   if(align && (len >= 4)) {
-    // Pre-load the temp registers
+    /* 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;
@@ -4489,16 +4805,18 @@
     data += 4-align;
     len -= 4-align;
 
-    int32_t sl = 8 * (4-align);
-    int32_t sr = 8 * align;
+    sl = 8 * (4-align);
+    sr = 8 * align;
 
-    // Mix
+    /* Mix */
 
     while(len >= 4) {
+      uint32_t k;
+
       d = *(uint32_t *)data;
       t = (t >> sr) | (d << sl);
 
-      uint32_t k = t;
+      k = t;
 
       MIX(h,k,m);
 
@@ -4508,25 +4826,27 @@
       len -= 4;
     }
 
-    // Handle leftover data in temp registers
+    /* 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];
       }
 
-      uint32_t k = (t >> sr) | (d << sl);
+      k = (t >> sr) | (d << sl);
       MIX(h,k,m);
 
       data += align;
       len -= align;
 
-      //----------
-      // Handle tail bytes
+      /* ----------
+       * Handle tail bytes */
 
       switch(len) {
         case 3: h ^= data[2] << 16;
@@ -4557,8 +4877,8 @@
       len -= 4;
     }
 
-    //----------
-    // Handle tail bytes
+    /* ----------
+     * Handle tail bytes */
 
     switch(len) {
       case 3: h ^= data[2] << 16;
@@ -4575,13 +4895,7 @@
 }
 #undef MIX
 
-#endif // UPB_UNALIGNED_READS_OK
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
+#endif /* UPB_UNALIGNED_READS_OK */
 
 #include <errno.h>
 #include <stdarg.h>
@@ -4597,10 +4911,10 @@
   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.
+/* 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);
@@ -4642,7 +4956,7 @@
 void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
   if (!status) return;
   status->ok_ = false;
-  vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+  _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args);
   nullz(status);
 }
 
@@ -4659,9 +4973,9 @@
   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.
+/* 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];
@@ -4669,7 +4983,7 @@
 static const upb_enumdef enums[4];
 static const upb_tabent strentries[236];
 static const upb_tabent intentries[14];
-static const _upb_value arrays[232];
+static const upb_tabval arrays[232];
 
 #ifdef UPB_DEBUG_REFS
 static upb_inttable reftables[212];
@@ -4702,21 +5016,21 @@
   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], UPB_UPCAST(&enums[2]), 6, 1, {0},&reftables[46], &reftables[47]),
+  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], UPB_UPCAST(&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], UPB_UPCAST(&msgs[2]), 13, 1, {0},&reftables[60], &reftables[61]),
+  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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&msgs[8]), 5, 0, {0},&reftables[74], &reftables[75]),
+  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]),
@@ -4726,16 +5040,16 @@
   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], UPB_UPCAST(&enums[0]), 11, 4, {0},&reftables[94], &reftables[95]),
+  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], UPB_UPCAST(&msgs[17]), 5, 0, {0},&reftables[100], &reftables[101]),
+  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], UPB_UPCAST(&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], UPB_UPCAST(&msgs[12]), 6, 0, {0},&reftables[106], &reftables[107]),
+  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], UPB_UPCAST(&msgs[19]), 5, 0, {0},&reftables[112], &reftables[113]),
+  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]),
@@ -4743,18 +5057,18 @@
   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], UPB_UPCAST(&msgs[0]), 13, 1, {0},&reftables[128], &reftables[129]),
+  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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&msgs[13]), 3, 0, {0},&reftables[150], &reftables[151]),
+  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]),
@@ -4762,22 +5076,22 @@
   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], UPB_UPCAST(&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], UPB_UPCAST(&msgs[16]), 21, 5, {0},&reftables[168], &reftables[169]),
+  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], UPB_UPCAST(&enums[1]), 12, 5, {0},&reftables[178], &reftables[179]),
+  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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&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], UPB_UPCAST(&msgs[4]), 6, 0, {0},&reftables[196], &reftables[197]),
+  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]),
 };
@@ -4790,494 +5104,494 @@
 };
 
 static const upb_tabent strentries[236] = {
-  {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&fields[14]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[38]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("field"), UPB_VALUE_INIT_CONSTPTR(&fields[16]), NULL},
-  {UPB_TABKEY_STR("extension_range"), UPB_VALUE_INIT_CONSTPTR(&fields[15]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("nested_type"), UPB_VALUE_INIT_CONSTPTR(&fields[44]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[49]), NULL},
-  {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&fields[9]), &strentries[14]},
-  {UPB_TABKEY_STR("start"), UPB_VALUE_INIT_CONSTPTR(&fields[66]), NULL},
-  {UPB_TABKEY_STR("end"), UPB_VALUE_INIT_CONSTPTR(&fields[8]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("value"), UPB_VALUE_INIT_CONSTPTR(&fields[78]), NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[50]), NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[40]), &strentries[22]},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[73]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("allow_alias"), UPB_VALUE_INIT_CONSTPTR(&fields[1]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&fields[47]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[52]), NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[37]), &strentries[30]},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[71]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("label"), UPB_VALUE_INIT_CONSTPTR(&fields[27]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[41]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&fields[46]), &strentries[49]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("type_name"), UPB_VALUE_INIT_CONSTPTR(&fields[70]), NULL},
-  {UPB_TABKEY_STR("extendee"), UPB_VALUE_INIT_CONSTPTR(&fields[12]), NULL},
-  {UPB_TABKEY_STR("type"), UPB_VALUE_INIT_CONSTPTR(&fields[69]), &strentries[48]},
-  {UPB_TABKEY_STR("default_value"), UPB_VALUE_INIT_CONSTPTR(&fields[4]), NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[51]), NULL},
-  {UPB_TABKEY_STR("experimental_map_key"), UPB_VALUE_INIT_CONSTPTR(&fields[11]), &strentries[67]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("weak"), UPB_VALUE_INIT_CONSTPTR(&fields[79]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("packed"), UPB_VALUE_INIT_CONSTPTR(&fields[58]), NULL},
-  {UPB_TABKEY_STR("lazy"), UPB_VALUE_INIT_CONSTPTR(&fields[28]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("ctype"), UPB_VALUE_INIT_CONSTPTR(&fields[3]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("deprecated"), UPB_VALUE_INIT_CONSTPTR(&fields[6]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[77]), NULL},
-  {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&fields[13]), NULL},
-  {UPB_TABKEY_STR("weak_dependency"), UPB_VALUE_INIT_CONSTPTR(&fields[80]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[34]), NULL},
-  {UPB_TABKEY_STR("service"), UPB_VALUE_INIT_CONSTPTR(&fields[63]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("source_code_info"), UPB_VALUE_INIT_CONSTPTR(&fields[64]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("dependency"), UPB_VALUE_INIT_CONSTPTR(&fields[5]), NULL},
-  {UPB_TABKEY_STR("message_type"), UPB_VALUE_INIT_CONSTPTR(&fields[32]), NULL},
-  {UPB_TABKEY_STR("package"), UPB_VALUE_INIT_CONSTPTR(&fields[57]), NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[53]), &strentries[82]},
-  {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&fields[10]), NULL},
-  {UPB_TABKEY_STR("public_dependency"), UPB_VALUE_INIT_CONSTPTR(&fields[61]), &strentries[81]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("file"), UPB_VALUE_INIT_CONSTPTR(&fields[17]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[75]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("cc_generic_services"), UPB_VALUE_INIT_CONSTPTR(&fields[2]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("java_multiple_files"), UPB_VALUE_INIT_CONSTPTR(&fields[24]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("java_generic_services"), UPB_VALUE_INIT_CONSTPTR(&fields[23]), &strentries[102]},
-  {UPB_TABKEY_STR("java_generate_equals_and_hash"), UPB_VALUE_INIT_CONSTPTR(&fields[22]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("go_package"), UPB_VALUE_INIT_CONSTPTR(&fields[18]), NULL},
-  {UPB_TABKEY_STR("java_package"), UPB_VALUE_INIT_CONSTPTR(&fields[26]), NULL},
-  {UPB_TABKEY_STR("optimize_for"), UPB_VALUE_INIT_CONSTPTR(&fields[48]), NULL},
-  {UPB_TABKEY_STR("py_generic_services"), UPB_VALUE_INIT_CONSTPTR(&fields[62]), NULL},
-  {UPB_TABKEY_STR("java_outer_classname"), UPB_VALUE_INIT_CONSTPTR(&fields[25]), NULL},
-  {UPB_TABKEY_STR("message_set_wire_format"), UPB_VALUE_INIT_CONSTPTR(&fields[31]), &strentries[106]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[76]), NULL},
-  {UPB_TABKEY_STR("no_standard_descriptor_accessor"), UPB_VALUE_INIT_CONSTPTR(&fields[45]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[39]), NULL},
-  {UPB_TABKEY_STR("input_type"), UPB_VALUE_INIT_CONSTPTR(&fields[20]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("output_type"), UPB_VALUE_INIT_CONSTPTR(&fields[56]), NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[55]), NULL},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[74]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&fields[54]), &strentries[122]},
-  {UPB_TABKEY_STR("method"), UPB_VALUE_INIT_CONSTPTR(&fields[33]), NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[35]), &strentries[121]},
-  {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&fields[72]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("location"), UPB_VALUE_INIT_CONSTPTR(&fields[30]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("span"), UPB_VALUE_INIT_CONSTPTR(&fields[65]), &strentries[139]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("trailing_comments"), UPB_VALUE_INIT_CONSTPTR(&fields[68]), NULL},
-  {UPB_TABKEY_STR("leading_comments"), UPB_VALUE_INIT_CONSTPTR(&fields[29]), &strentries[137]},
-  {UPB_TABKEY_STR("path"), UPB_VALUE_INIT_CONSTPTR(&fields[59]), NULL},
-  {UPB_TABKEY_STR("double_value"), UPB_VALUE_INIT_CONSTPTR(&fields[7]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&fields[36]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("negative_int_value"), UPB_VALUE_INIT_CONSTPTR(&fields[43]), NULL},
-  {UPB_TABKEY_STR("aggregate_value"), UPB_VALUE_INIT_CONSTPTR(&fields[0]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("positive_int_value"), UPB_VALUE_INIT_CONSTPTR(&fields[60]), NULL},
-  {UPB_TABKEY_STR("identifier_value"), UPB_VALUE_INIT_CONSTPTR(&fields[19]), NULL},
-  {UPB_TABKEY_STR("string_value"), UPB_VALUE_INIT_CONSTPTR(&fields[67]), &strentries[154]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("is_extension"), UPB_VALUE_INIT_CONSTPTR(&fields[21]), NULL},
-  {UPB_TABKEY_STR("name_part"), UPB_VALUE_INIT_CONSTPTR(&fields[42]), NULL},
-  {UPB_TABKEY_STR("LABEL_REQUIRED"), UPB_VALUE_INIT_INT32(2), &strentries[162]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("LABEL_REPEATED"), UPB_VALUE_INIT_INT32(3), NULL},
-  {UPB_TABKEY_STR("LABEL_OPTIONAL"), UPB_VALUE_INIT_INT32(1), NULL},
-  {UPB_TABKEY_STR("TYPE_FIXED64"), UPB_VALUE_INIT_INT32(6), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_STRING"), UPB_VALUE_INIT_INT32(9), NULL},
-  {UPB_TABKEY_STR("TYPE_FLOAT"), UPB_VALUE_INIT_INT32(2), &strentries[193]},
-  {UPB_TABKEY_STR("TYPE_DOUBLE"), UPB_VALUE_INIT_INT32(1), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_INT32"), UPB_VALUE_INIT_INT32(5), NULL},
-  {UPB_TABKEY_STR("TYPE_SFIXED32"), UPB_VALUE_INIT_INT32(15), NULL},
-  {UPB_TABKEY_STR("TYPE_FIXED32"), UPB_VALUE_INIT_INT32(7), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_MESSAGE"), UPB_VALUE_INIT_INT32(11), &strentries[194]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_INT64"), UPB_VALUE_INIT_INT32(3), &strentries[191]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_ENUM"), UPB_VALUE_INIT_INT32(14), NULL},
-  {UPB_TABKEY_STR("TYPE_UINT32"), UPB_VALUE_INIT_INT32(13), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_UINT64"), UPB_VALUE_INIT_INT32(4), &strentries[190]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("TYPE_SFIXED64"), UPB_VALUE_INIT_INT32(16), NULL},
-  {UPB_TABKEY_STR("TYPE_BYTES"), UPB_VALUE_INIT_INT32(12), NULL},
-  {UPB_TABKEY_STR("TYPE_SINT64"), UPB_VALUE_INIT_INT32(18), NULL},
-  {UPB_TABKEY_STR("TYPE_BOOL"), UPB_VALUE_INIT_INT32(8), NULL},
-  {UPB_TABKEY_STR("TYPE_GROUP"), UPB_VALUE_INIT_INT32(10), NULL},
-  {UPB_TABKEY_STR("TYPE_SINT32"), UPB_VALUE_INIT_INT32(17), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("CORD"), UPB_VALUE_INIT_INT32(1), NULL},
-  {UPB_TABKEY_STR("STRING"), UPB_VALUE_INIT_INT32(0), &strentries[197]},
-  {UPB_TABKEY_STR("STRING_PIECE"), UPB_VALUE_INIT_INT32(2), NULL},
-  {UPB_TABKEY_STR("CODE_SIZE"), UPB_VALUE_INIT_INT32(2), NULL},
-  {UPB_TABKEY_STR("SPEED"), UPB_VALUE_INIT_INT32(1), &strentries[203]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("LITE_RUNTIME"), UPB_VALUE_INIT_INT32(3), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("google.protobuf.SourceCodeInfo.Location"), UPB_VALUE_INIT_CONSTPTR(&msgs[17]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.UninterpretedOption"), UPB_VALUE_INIT_CONSTPTR(&msgs[18]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FileDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[8]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.MethodDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[12]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("google.protobuf.EnumValueOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[5]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("google.protobuf.DescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[0]), &strentries[228]},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("google.protobuf.SourceCodeInfo"), UPB_VALUE_INIT_CONSTPTR(&msgs[16]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FieldDescriptorProto.Type"), UPB_VALUE_INIT_CONSTPTR(&enums[1]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.DescriptorProto.ExtensionRange"), UPB_VALUE_INIT_CONSTPTR(&msgs[1]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_STR("google.protobuf.EnumValueDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[4]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FieldOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[7]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FileOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[10]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.EnumDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[2]), &strentries[233]},
-  {UPB_TABKEY_STR("google.protobuf.FieldDescriptorProto.Label"), UPB_VALUE_INIT_CONSTPTR(&enums[0]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.ServiceDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[14]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FieldOptions.CType"), UPB_VALUE_INIT_CONSTPTR(&enums[2]), &strentries[229]},
-  {UPB_TABKEY_STR("google.protobuf.FileDescriptorSet"), UPB_VALUE_INIT_CONSTPTR(&msgs[9]), &strentries[235]},
-  {UPB_TABKEY_STR("google.protobuf.EnumOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[3]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FieldDescriptorProto"), UPB_VALUE_INIT_CONSTPTR(&msgs[6]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.FileOptions.OptimizeMode"), UPB_VALUE_INIT_CONSTPTR(&enums[3]), &strentries[221]},
-  {UPB_TABKEY_STR("google.protobuf.ServiceOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[15]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.MessageOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[11]), NULL},
-  {UPB_TABKEY_STR("google.protobuf.MethodOptions"), UPB_VALUE_INIT_CONSTPTR(&msgs[13]), &strentries[226]},
-  {UPB_TABKEY_STR("google.protobuf.UninterpretedOption.NamePart"), UPB_VALUE_INIT_CONSTPTR(&msgs[19]), NULL},
+  {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__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[73]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[71]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[77]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[75]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[76]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[74]), NULL},
-  {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
-  {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&fields[72]), NULL},
+  {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_value arrays[232] = {
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[38]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[16]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[44]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[9]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[15]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[14]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[49]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[66]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[8]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[40]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[78]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[50]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[1]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[37]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[47]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[52]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[41]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[12]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[46]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[27]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[69]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[70]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[4]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[51]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[3]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[58]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[6]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[28]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[11]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[79]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[34]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[57]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[5]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[32]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[10]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[63]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[13]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[53]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[64]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[61]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[80]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[17]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[26]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[25]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[48]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[24]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[18]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[2]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[23]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[62]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[22]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[31]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[45]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[39]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[20]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[56]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[55]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[35]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[33]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[54]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[30]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[59]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[65]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[29]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[68]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[36]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[19]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[60]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[43]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[7]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[67]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[0]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR(&fields[42]),
-  UPB_VALUE_INIT_CONSTPTR(&fields[21]),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR("LABEL_OPTIONAL"),
-  UPB_VALUE_INIT_CONSTPTR("LABEL_REQUIRED"),
-  UPB_VALUE_INIT_CONSTPTR("LABEL_REPEATED"),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR("TYPE_DOUBLE"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_FLOAT"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_INT64"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_UINT64"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_INT32"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED64"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_GROUP"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_MESSAGE"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_BYTES"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_UINT32"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_ENUM"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"),
-  UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"),
-  UPB_VALUE_INIT_CONSTPTR("STRING"),
-  UPB_VALUE_INIT_CONSTPTR("CORD"),
-  UPB_VALUE_INIT_CONSTPTR("STRING_PIECE"),
-  UPB_ARRAY_EMPTYENT,
-  UPB_VALUE_INIT_CONSTPTR("SPEED"),
-  UPB_VALUE_INIT_CONSTPTR("CODE_SIZE"),
-  UPB_VALUE_INIT_CONSTPTR("LITE_RUNTIME"),
+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]);
@@ -5505,23 +5819,66 @@
 #endif
 
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2008-2009 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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;
@@ -5530,11 +5887,11 @@
   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.
+/* 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);
@@ -5559,8 +5916,9 @@
 }
 
 void upb_deflist_uninit(upb_deflist *l) {
+  size_t i;
   if (l->owned)
-    for(size_t i = 0; i < l->len; i++)
+    for(i = 0; i < l->len; i++)
       upb_def_unref(l->defs[i], l);
   free(l->defs);
 }
@@ -5578,8 +5936,9 @@
 }
 
 void upb_deflist_donaterefs(upb_deflist *l, void *owner) {
+  size_t i;
   assert(l->owned);
-  for (size_t i = 0; i < l->len; i++)
+  for (i = 0; i < l->len; i++)
     upb_def_donateref(l->defs[i], l, owner);
   l->owned = false;
 }
@@ -5588,9 +5947,10 @@
   return l->defs[l->len-1];
 }
 
-// Qualify the defname for all defs starting with offset "start" with "str".
+/* 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) {
-  for (uint32_t i = start; i < l->len; i++) {
+  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);
@@ -5601,39 +5961,10 @@
 
 /* upb_descreader  ************************************************************/
 
-void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
-                         upb_status *status) {
-  UPB_UNUSED(status);
-  upb_deflist_init(&r->defs);
-  upb_sink_reset(upb_descreader_input(r), handlers, r);
-  r->stack_len = 0;
-  r->name = NULL;
-  r->default_string = NULL;
-}
-
-void upb_descreader_uninit(upb_descreader *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);
-  }
-}
-
-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;
-}
-
 static upb_msgdef *upb_descreader_top(upb_descreader *r) {
+  int index;
   assert(r->stack_len > 1);
-  int index = r->stack[r->stack_len-1].start - 1;
+  index = r->stack[r->stack_len-1].start - 1;
   assert(index >= 0);
   return upb_downcast_msgdef_mutable(r->defs.defs[index]);
 }
@@ -5642,8 +5973,8 @@
   return upb_deflist_last(&r->defs);
 }
 
-// Start/end handlers for FileDescriptorProto and DescriptorProto (the two
-// entities that have names and can contain sub-definitions.
+/* 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;
@@ -5663,7 +5994,7 @@
   f->name = str;
 }
 
-// Handlers for google.protobuf.FileDescriptorProto.
+/* Handlers for google.protobuf.FileDescriptorProto. */
 static bool file_startmsg(void *r, const void *hd) {
   UPB_UNUSED(hd);
   upb_descreader_startcontainer(r);
@@ -5671,27 +6002,27 @@
 }
 
 static bool file_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
   UPB_UNUSED(hd);
   UPB_UNUSED(status);
-  upb_descreader *r = closure;
   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);
-  upb_descreader *r = closure;
-  // XXX: see comment at the top of the file.
+  /* XXX: see comment at the top of the file. */
   upb_descreader_setscopename(r, upb_strndup(buf, n));
   return n;
 }
 
-// Handlers for google.protobuf.EnumValueDescriptorProto.
+/* Handlers for google.protobuf.EnumValueDescriptorProto. */
 static bool enumval_startmsg(void *closure, const void *hd) {
-  UPB_UNUSED(hd);
   upb_descreader *r = closure;
+  UPB_UNUSED(hd);
   r->saw_number = false;
   r->saw_name = false;
   return true;
@@ -5699,10 +6030,10 @@
 
 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);
-  upb_descreader *r = closure;
-  // XXX: see comment at the top of the file.
+  /* XXX: see comment at the top of the file. */
   free(r->name);
   r->name = upb_strndup(buf, n);
   r->saw_name = true;
@@ -5710,21 +6041,23 @@
 }
 
 static bool enumval_onnumber(void *closure, const void *hd, int32_t val) {
-  UPB_UNUSED(hd);
   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_UNUSED(hd);
   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;
   }
-  upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
   upb_enumdef_addval(e, r->name, r->number, status);
   free(r->name);
   r->name = NULL;
@@ -5732,18 +6065,21 @@
 }
 
 
-// Handlers for google.protobuf.EnumDescriptorProto.
+/* Handlers for google.protobuf.EnumDescriptorProto. */
 static bool enum_startmsg(void *closure, const void *hd) {
-  UPB_UNUSED(hd);
   upb_descreader *r = closure;
-  upb_deflist_push(&r->defs, UPB_UPCAST(upb_enumdef_new(&r->defs)));
+  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_UNUSED(hd);
   upb_descreader *r = closure;
-  upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  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;
@@ -5757,31 +6093,31 @@
 
 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);
-  upb_descreader *r = closure;
-  // XXX: see comment at the top of the file.
-  char *fullname = upb_strndup(buf, n);
+  /* 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
+/* Handlers for google.protobuf.FieldDescriptorProto */
 static bool field_startmsg(void *closure, const void *hd) {
-  UPB_UNUSED(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.
+  /* 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.
+/* 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;
@@ -5795,7 +6131,8 @@
       break;
     }
     case UPB_TYPE_INT64: {
-      long long val = strtoll(str, &end, 0);
+      /* 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
@@ -5803,7 +6140,7 @@
       break;
     }
     case UPB_TYPE_UINT32: {
-      long val = strtoul(str, &end, 0);
+      unsigned long val = strtoul(str, &end, 0);
       if (val > UINT32_MAX || errno == ERANGE || *end)
         success = false;
       else
@@ -5811,7 +6148,8 @@
       break;
     }
     case UPB_TYPE_UINT64: {
-      unsigned long long val = strtoull(str, &end, 0);
+      /* 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
@@ -5827,7 +6165,8 @@
       break;
     }
     case UPB_TYPE_FLOAT: {
-      float val = strtof(str, &end);
+      /* 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
@@ -5849,10 +6188,11 @@
 }
 
 static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
-  UPB_UNUSED(hd);
   upb_descreader *r = closure;
   upb_fielddef *f = r->f;
-  // TODO: verify that all required fields were present.
+  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));
@@ -5866,8 +6206,8 @@
       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.
+        /* 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;
       }
@@ -5877,48 +6217,54 @@
 }
 
 static bool field_onlazy(void *closure, const void *hd, bool val) {
-  UPB_UNUSED(hd);
   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_UNUSED(hd);
   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_UNUSED(hd);
   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_UNUSED(hd);
   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_UNUSED(hd);
   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);
-  upb_descreader *r = closure;
-  // XXX: see comment at the top of the file.
-  char *name = upb_strndup(buf, n);
+
+  /* XXX: see comment at the top of the file. */
   upb_fielddef_setname(r->f, name, NULL);
   free(name);
   return n;
@@ -5926,11 +6272,12 @@
 
 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);
-  upb_descreader *r = closure;
-  // XXX: see comment at the top of the file.
-  char *name = upb_strndup(buf, n);
+
+  /* XXX: see comment at the top of the file. */
   upb_fielddef_setsubdefname(r->f, name, NULL);
   free(name);
   return n;
@@ -5938,11 +6285,12 @@
 
 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);
-  upb_descreader *r = closure;
-  // XXX: see comment at the top of the file.
-  char *name = upb_strndup(buf, n);
+
+  /* XXX: see comment at the top of the file. */
   upb_fielddef_setcontainingtypename(r->f, name, NULL);
   free(name);
   return n;
@@ -5950,31 +6298,35 @@
 
 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);
-  upb_descreader *r = closure;
-  // 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.
+
+  /* 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).
+/* Handlers for google.protobuf.DescriptorProto (representing a message). */
 static bool msg_startmsg(void *closure, const void *hd) {
-  UPB_UNUSED(hd);
   upb_descreader *r = closure;
-  upb_deflist_push(&r->defs, UPB_UPCAST(upb_msgdef_new(&r->defs)));
+  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_UNUSED(hd);
   upb_descreader *r = closure;
   upb_msgdef *m = upb_descreader_top(r);
-  if(!upb_def_fullname(UPB_UPCAST(m))) {
+  UPB_UNUSED(hd);
+
+  if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) {
     upb_status_seterrmsg(status, "Encountered message with no name.");
     return false;
   }
@@ -5984,32 +6336,35 @@
 
 static size_t msg_onname(void *closure, const void *hd, const char *buf,
                          size_t n, const upb_bufhandle *handle) {
-  UPB_UNUSED(hd);
-  UPB_UNUSED(handle);
   upb_descreader *r = closure;
   upb_msgdef *m = upb_descreader_top(r);
-  // XXX: see comment at the top of the file.
+  /* XXX: see comment at the top of the file. */
   char *name = upb_strndup(buf, n);
-  upb_def_setfullname(UPB_UPCAST(m), name, NULL);
-  upb_descreader_setscopename(r, name);  // Passes ownership of name.
+  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_UNUSED(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_UNUSED(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_UPCAST(r->f));
+  upb_deflist_push(&r->defs, upb_fielddef_upcast_mutable(r->f));
   r->f = NULL;
   return true;
 }
@@ -6070,6 +6425,45 @@
 
 #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(
@@ -6078,21 +6472,18 @@
   return h;
 }
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2013 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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>
 
@@ -6122,14 +6513,14 @@
   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_UPCAST(method), closure);
+    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(UPB_UPCAST(g), &vtbl, owner);
+  upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner);
   upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
   g->bytecode = NULL;
   g->bytecode_end = NULL;
@@ -6141,7 +6532,6 @@
 
 static void freemethod(upb_refcounted *r) {
   upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
-  upb_byteshandler_uninit(&method->input_handler_);
 
   if (method->dest_handlers_) {
     upb_handlers_unref(method->dest_handlers_, method);
@@ -6161,18 +6551,18 @@
                                       mgroup *group) {
   static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
   upb_pbdecodermethod *ret = malloc(sizeof(*ret));
-  upb_refcounted_init(UPB_UPCAST(ret), &vtbl, &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.
+  /* 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_refcounted_unref(UPB_UPCAST(ret), &ret);
+  upb_pbdecodermethod_unref(ret, &ret);
 
-  ret->group = UPB_UPCAST(group);
+  ret->group = mgroup_upcast_mutable(group);
   ret->dest_handlers_ = dest_handlers;
-  ret->is_native_ = false;  // If we JIT, it will update this later.
+  ret->is_native_ = false;  /* If we JIT, it will update this later. */
   upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
 
   if (ret->dest_handlers_) {
@@ -6181,25 +6571,6 @@
   return ret;
 }
 
-void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner) {
-  upb_refcounted_ref(UPB_UPCAST(m), owner);
-}
-
-void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m,
-                               const void *owner) {
-  upb_refcounted_unref(UPB_UPCAST(m), owner);
-}
-
-void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
-                                   const void *from, const void *to) {
-  upb_refcounted_donateref(UPB_UPCAST(m), from, to);
-}
-
-void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
-                                  const void *owner) {
-  upb_refcounted_checkref(UPB_UPCAST(m), owner);
-}
-
 const upb_handlers *upb_pbdecodermethod_desthandlers(
     const upb_pbdecodermethod *m) {
   return m->dest_handlers_;
@@ -6216,10 +6587,11 @@
 
 const upb_pbdecodermethod *upb_pbdecodermethod_new(
     const upb_pbdecodermethodopts *opts, const void *owner) {
+  const upb_pbdecodermethod *ret;
   upb_pbcodecache cache;
+
   upb_pbcodecache_init(&cache);
-  const upb_pbdecodermethod *ret =
-      upb_pbcodecache_getdecodermethod(&cache, opts);
+  ret = upb_pbcodecache_getdecodermethod(&cache, opts);
   upb_pbdecodermethod_ref(ret, owner);
   upb_pbcodecache_uninit(&cache);
   return ret;
@@ -6228,7 +6600,7 @@
 
 /* bytecode compiler **********************************************************/
 
-// Data used only at compilation time.
+/* Data used only at compilation time. */
 typedef struct {
   mgroup *group;
 
@@ -6236,15 +6608,17 @@
   int fwd_labels[MAXLABEL];
   int back_labels[MAXLABEL];
 
-  // For fields marked "lazy", parse them lazily or eagerly?
+  /* 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 (int i = 0; i < MAXLABEL; i++) {
+  for (i = 0; i < MAXLABEL; i++) {
     ret->fwd_labels[i] = EMPTYLABEL;
     ret->back_labels[i] = EMPTYLABEL;
   }
@@ -6257,7 +6631,7 @@
 
 const size_t ptr_words = sizeof(void*) / sizeof(uint32_t);
 
-// How many words an instruction is.
+/* How many words an instruction is. */
 static int instruction_len(uint32_t instr) {
   switch (getop(instr)) {
     case OP_SETDISPATCH: return 1 + ptr_words;
@@ -6273,8 +6647,8 @@
     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.
+    /* 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:
@@ -6299,18 +6673,21 @@
   } else {
     *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8);
   }
-  assert(getofs(*instruction) == ofs);  // Would fail in cases of overflow.
+  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.
+/* 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);
-  int val = c->fwd_labels[label];
-  uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
+  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));
@@ -6320,24 +6697,25 @@
   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.
+/* 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.
+    /* No resolving required. */
     return 0;
   } else if (label < 0) {
-    // Backward local label.  Relative to the next instruction.
+    /* 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.
+    /* 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);
@@ -6351,7 +6729,7 @@
     int ofs = pcofs(c);
     size_t oldsize = g->bytecode_end - g->bytecode;
     size_t newsize = UPB_MAX(oldsize * 2, 64);
-    // TODO(haberman): handle OOM.
+    /* TODO(haberman): handle OOM. */
     g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t));
     g->bytecode_end = g->bytecode + newsize;
     c->pc = g->bytecode + ofs;
@@ -6450,19 +6828,22 @@
 #if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE)
 
 const char *upb_pbdecoder_getopname(unsigned int op) {
-#define OP(op) [OP_ ## op] = "OP_" #op
-#define T(op) OP(PARSE_##op)
-  static const char *names[] = {
-    "<no opcode>",
-    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 op > OP_HALT ? names[0] : names[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
 }
@@ -6560,7 +6941,7 @@
 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.
+  /* No tag should be greater than 5 bytes. */
   assert(encoded_tag <= 0xffffffffff);
   return encoded_tag;
 }
@@ -6588,29 +6969,29 @@
   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.
+/* 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.
+  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.
+/* 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.
+  /* 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.
+    /* 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));
@@ -6652,8 +7033,8 @@
   }
 }
 
-// Puts an opcode to call a callback, but only if a callback actually exists for
-// this field and handler type.
+/* 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);
@@ -6671,27 +7052,28 @@
 
 /* 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.
+/* 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.
+/* 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.
+    /* Don't emit any code for this field at all; it will be parsed as an
+     * unknown field. */
     return;
   }
 
   label(c, LABEL_FIELD);
 
-  int wire_type =
+  wire_type =
       (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE)
           ? UPB_WIRE_TYPE_DELIMITED
           : UPB_WIRE_TYPE_START_GROUP;
@@ -6732,7 +7114,7 @@
   }
 }
 
-// Generates bytecode to parse a single string or lazy submessage field.
+/* 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);
@@ -6747,7 +7129,7 @@
    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.
+    /* 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);
@@ -6771,49 +7153,52 @@
   }
 }
 
-// Generates bytecode to parse a single primitive field.
+/* Generates bytecode to parse a single primitive field. */
 static void generate_primitivefield(compiler *c, const upb_fielddef *f,
                                     upb_pbdecodermethod *method) {
-  label(c, LABEL_FIELD);
-
   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;
 
-  // From a decoding perspective, ENUM is the same as INT32.
+  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;
 
-  opcode parse_type = (opcode)descriptor_type;
+  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.
+  /* 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);
-  upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
-  int wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+  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
+    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
+    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.
+    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.
+    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);
@@ -6822,24 +7207,29 @@
   }
 }
 
-// Adds bytecode for parsing the given message to the given decoderplan,
-// while adding all dispatch targets to this message's dispatch table.
+/* 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.
+  /* Clear all entries in the dispatch table. */
   upb_inttable_uninit(&method->dispatch);
   upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
 
-  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
-  const upb_msgdef *md = upb_handlers_msgdef(h);
+  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);
-  uint32_t* start_pc = c->pc;
-  upb_msg_field_iter i;
+  start_pc = c->pc;
   for(upb_msg_field_begin(&i, md);
       !upb_msg_field_done(&i);
       upb_msg_field_next(&i)) {
@@ -6856,23 +7246,23 @@
     }
   }
 
-  // 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 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.
+    /* Check for end-of-message. */
     putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
-    // Unconditionally dispatch.
+    /* 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).
+  /* 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.
+  /* Insert both a label and a dispatch table entry for this end-of-msg. */
  label(c, LABEL_ENDMSG);
-  upb_value val = upb_value_uint64(pcofs(c) - method->code_base.ofs);
+  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);
@@ -6881,19 +7271,21 @@
   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".
+/* 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.
-  upb_msg_field_iter i;
-  const upb_msgdef *md = upb_handlers_msgdef(h);
+  /* Find submethods. */
+  md = upb_handlers_msgdef(h);
   for(upb_msg_field_begin(&i, md);
       !upb_msg_field_done(&i);
       upb_msg_field_next(&i)) {
@@ -6901,20 +7293,21 @@
     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.
+      /* 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".
+/* (Re-)compile bytecode for all messages in "msgs."
+ * Overwrites any existing bytecode in "c". */
 static void compile_methods(compiler *c) {
-  // Start over at the beginning of the bytecode.
+  upb_inttable_iter i;
+
+  /* Start over at the beginning of the bytecode. */
   c->pc = c->group->bytecode;
 
-  upb_inttable_iter i;
   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));
@@ -6927,10 +7320,10 @@
   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 *h = &m->input_handler_;
     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);
@@ -6945,53 +7338,58 @@
 static void sethandlers(mgroup *g, bool allowjit) {
   g->jit_code = NULL;
   if (allowjit) {
-    // Compile byte-code into machine code, create handlers.
+    /* Compile byte-code into machine code, create handlers. */
     upb_pbdecoder_jit(g);
   } else {
     set_bytecode_handlers(g);
   }
 }
 
-#else  // UPB_USE_JIT_X64
+#else  /* UPB_USE_JIT_X64 */
 
 static void sethandlers(mgroup *g, bool allowjit) {
-  // No JIT compiled in; use bytecode handlers unconditionally.
+  /* No JIT compiled in; use bytecode handlers unconditionally. */
   UPB_UNUSED(allowjit);
   set_bytecode_handlers(g);
 }
 
-#endif  // UPB_USE_JIT_X64
+#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).
+/* 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));
 
-  mgroup *g = newgroup(owner);
-  compiler *c = newcompiler(g, lazy);
+  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.
+  /* 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);
+  {
+    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);
@@ -7011,7 +7409,7 @@
   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));
-    upb_refcounted_unref(UPB_UPCAST(group), c);
+    mgroup_unref(group, c);
   }
   upb_inttable_uninit(&c->groups);
 }
@@ -7029,13 +7427,15 @@
 
 const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
     upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) {
-  // Right now we build a new DecoderMethod every time.
-  // TODO(haberman): properly cache methods by their true key.
+  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));
 
-  upb_value v;
-  bool ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v);
+  ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v);
   UPB_ASSERT_VAR(ok, ok);
   return upb_value_getptr(v);
 }
@@ -7053,30 +7453,22 @@
   opts->lazy = lazy;
 }
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2008-2013 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * This file implements a VM for the interpreted (bytecode) decoder.
- *
- * 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.
- */
+** 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 <setjmp.h>
-#include <stdarg.h>
 #include <stddef.h>
-#include <stdlib.h>
 
 #ifdef UPB_DUMP_BYTECODE
 #include <stdio.h>
@@ -7084,17 +7476,19 @@
 
 #define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d);
 
-// Error messages that are shared between the bytecode and JIT decoders.
+/* 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.
+/* 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.
+/* Whether an op consumes any of the input buffer. */
 static bool consumes_input(opcode op) {
   switch (op) {
     case OP_SETDISPATCH:
@@ -7120,20 +7514,41 @@
   }
 }
 
+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 this way,
-// especially since this tuning is necessarily specific to one hardware
-// configuration.  But emperically 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.
-#define FORCEINLINE static inline __attribute__((always_inline))
-#define NOINLINE __attribute__((noinline))
+/* 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) {
-  // TODO(haberman): encapsulate this access to pipeline->status, but not sure
-  // exactly what that interface should look like.
-  upb_status_seterrmsg(d->status, 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) {
@@ -7143,22 +7558,32 @@
 
 /* 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.
+/* 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.
+/* 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;
 }
 
-// Overall stream offset of 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);
 }
 
-// Advances d->ptr.
+/* 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;
@@ -7172,11 +7597,11 @@
   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.
+/* 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 <= (d->end - d->buf)) {
+  if (delim_ofs <= (size_t)(d->end - d->buf)) {
     d->delim_end = d->buf + delim_ofs;
     d->data_end = d->delim_end;
   } else {
@@ -7199,46 +7624,96 @@
 }
 
 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.
+  /* 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;
 }
 
-// Resumes the decoder from an initial state or from a previous suspend.
+/* 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.
+  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.
+    /* 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.
+/* 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.
+    /* 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);
-    size_t consumed = d->checkpoint - d->buf;
+
+    consumed = d->checkpoint - d->buf;
     d->bufstart_ofs += consumed;
     d->residual_end = d->residual;
     switchtobuf(d, d->residual, d->residual_end);
@@ -7246,17 +7721,17 @@
   }
 }
 
-// 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.
+/* 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.
+  /* 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.
+    /* 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)) {
@@ -7265,10 +7740,12 @@
     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.
+    /* Checkpoint was in user buf; old residual bytes not needed. */
+    size_t save;
     assert(!in_residual_buf(d, d->checkpoint));
+
     d->ptr = d->checkpoint;
-    size_t save = curbufleft(d);
+    save = curbufleft(d);
     assert(save <= sizeof(d->residual));
     memcpy(d->residual, d->ptr, save);
     d->residual_end = d->residual + save;
@@ -7279,39 +7756,20 @@
   return d->size_param;
 }
 
-// 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 the caller should skip before passing a new buffer.
-static int32_t skip(upb_pbdecoder *d, size_t bytes) {
-  assert(!in_residual_buf(d, d->ptr) || d->size_param == 0);
-  if (curbufleft(d) >= bytes) {
-    // Skipped data is all in current buffer.
-    advance(d, bytes);
-    return DECODE_OK;
-  } else {
-    // Skipped data extends beyond currently available buffers.
-    d->pc = d->last;
-    size_t skip = bytes - curbufleft(d);
-    d->bufstart_ofs += (d->end - d->buf) + skip;
-    d->residual_end = d->residual;
-    switchtobuf(d, d->residual, d->residual_end);
-    return d->size_param + skip;
-  }
-}
-
-// Copies the next "bytes" bytes into "buf" and advances the stream.
-// Requires that this many bytes are available in the current buffer.
-FORCEINLINE void consumebytes(upb_pbdecoder *d, void *buf, size_t bytes) {
+/* 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.
-static NOINLINE int32_t getbytes_slow(upb_pbdecoder *d, void *buf,
-                                      size_t 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;
@@ -7320,7 +7778,7 @@
     advancetobuf(d, d->buf_param, d->size_param);
   }
   if (curbufleft(d) >= bytes) {
-    consumebytes(d, buf + avail, 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");
@@ -7330,11 +7788,13 @@
   }
 }
 
-// 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.
-FORCEINLINE int32_t getbytes(upb_pbdecoder *d, void *buf, size_t bytes) {
+/* 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.
+    /* Buffer has enough data to satisfy. */
     consumebytes(d, buf, bytes);
     return DECODE_OK;
   } else {
@@ -7342,19 +7802,20 @@
   }
 }
 
-static NOINLINE size_t peekbytes_slow(upb_pbdecoder *d, void *buf,
-                                      size_t 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(buf + ret, d->buf_param, copy);
+    memcpy((char *)buf + ret, d->buf_param, copy);
     ret += copy;
   }
   return ret;
 }
 
-FORCEINLINE size_t peekbytes(upb_pbdecoder *d, void *buf, size_t bytes) {
+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;
@@ -7366,13 +7827,13 @@
 
 /* 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.
-NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d,
-                                                  uint64_t *u64) {
-  *u64 = 0;
+/* 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;
@@ -7385,15 +7846,15 @@
   return DECODE_OK;
 }
 
-// Decodes a varint from the current buffer position.
-// Returns a status code as described in decoder.int.h.
-FORCEINLINE int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) {
+/* 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.
+    /* Fast case. */
     upb_decoderet r = upb_vdecode_fast(d->ptr);
     if (r.p == NULL) {
       seterr(d, kUnterminatedVarint);
@@ -7403,22 +7864,23 @@
     *u64 = r.val;
     return DECODE_OK;
   } else {
-    // Slow case -- varint spans buffer seam.
+    /* 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.
-FORCEINLINE int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) {
+/* 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.
+    /* 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);
   }
@@ -7426,22 +7888,22 @@
   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.
-FORCEINLINE int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) {
+/* 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.
-FORCEINLINE int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) {
+/* 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.
+/* 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);
 }
@@ -7453,14 +7915,14 @@
 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.
+/* 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, "Submessage end extends past enclosing submessage.");
+    seterr(d, kPbDecoderSubmessageTooLong);
     return false;
-  } else if ((fr + 1) == d->limit) {
+  } else if (fr == d->limit) {
     seterr(d, kPbDecoderStackOverflow);
     return false;
   }
@@ -7474,26 +7936,26 @@
 }
 
 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.
+  /* 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.
+/* Pops a frame from the decoder stack. */
 static void decoder_pop(upb_pbdecoder *d) { d->top--; }
 
-NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d,
-                                             uint64_t expected) {
+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.
+    /* Advance past matched bytes. */
     int32_t ok = getbytes(d, &data, read);
     UPB_ASSERT_VAR(ok, ok < 0);
     return DECODE_OK;
@@ -7521,7 +7983,7 @@
       return upb_pbdecoder_suspend(d);
     }
 
-    // TODO: deliver to unknown field callback.
+    /* TODO: deliver to unknown field callback. */
     switch (wire_type) {
       case UPB_WIRE_TYPE_32BIT:
         CHECK_RETURN(skip(d, 4));
@@ -7562,34 +8024,7 @@
       return DECODE_OK;
     }
 
-    if (d->ptr == d->delim_end) {
-      seterr(d, "Enclosing submessage ended in the middle of value or group");
-      // Unlike most errors we notice during parsing, right now we have consumed
-      // all of the user's input.
-      //
-      // There are three different options for how to handle this case:
-      //
-      //   1. decode() = short count, error = set
-      //   2. decode() = full count, error = set
-      //   3. decode() = full count, error NOT set, short count and error will
-      //      be reported on next call to decode() (or end())
-      //
-      // (1) and (3) have the advantage that they preserve the invariant that an
-      // error occurs iff decode() returns a short count.
-      //
-      // (2) and (3) have the advantage of reflecting the fact that all of the
-      // bytes were in fact parsed (and possibly delivered to the unknown field
-      // handler, in the future when that is supported).
-      //
-      // (3) requires extra state in the decode (a place to store the "permanent
-      // error" that we should return for all subsequent attempts to decode).
-      // But we likely want this anyway.
-      //
-      // Right now we do (1), thanks to the fact that we checkpoint *after* this
-      // check.  (3) may be a better choice long term; unclear at the moment.
-      return upb_pbdecoder_suspend(d);
-    }
-
+    /* Unknown group -- continue looping over unknown fields. */
     checkpoint(d);
   }
 }
@@ -7601,24 +8036,27 @@
   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.
+/* 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;
-
-  // Decode tag.
   uint32_t tag;
-  CHECK_RETURN(decode_v32(d, &tag));
-  uint8_t wire_type = tag & 0x7;
-  uint32_t fieldnum = tag >> 3;
-
-  // Lookup tag.  Because of packed/non-packed compatibility, we have to
-  // check the wire type against two possibilities.
+  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);
@@ -7634,20 +8072,29 @@
     }
   }
 
-  // Unknown field or ENDGROUP.
-  int32_t ret = upb_pbdecoder_skipunknown(d, fieldnum, wire_type);
+  /* 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);
 
-  if (ret == DECODE_ENDGROUP) {
+  /* 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;
-  } else {
-    d->pc = d->last - 1;  // Rewind to CHECKDELIM.
-    return ret;
   }
+
+  return DECODE_OK;
 }
 
-// Callers know that the stack is more than one deep because the opcodes that
-// call this only occur after PUSH operations.
+/* 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;
@@ -7656,19 +8103,10 @@
 
 /* The main decoding loop *****************************************************/
 
-// The main decoder VM function.  Uses traditional bytecode dispatch loop with a
-// switch() statement.
-size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
-                            size_t size, const upb_bufhandle *handle) {
-  upb_pbdecoder *d = closure;
-  const mgroup *group = hd;
-  assert(buf);
-  int32_t result = upb_pbdecoder_resume(d, NULL, buf, size, handle);
-  if (result == DECODE_ENDGROUP) {
-    goto_endmsg(d);
-  }
-  CHECK_RETURN(result);
-  UPB_UNUSED(group);
+/* 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; }
@@ -7680,12 +8118,18 @@
   })
 
   while(1) {
+    int32_t instruction;
+    opcode op;
+    uint32_t arg;
+    int32_t longofs;
+
     d->last = d->pc;
-    int32_t instruction = *d->pc++;
-    opcode op = getop(instruction);
-    uint32_t arg = instruction >> 8;
-    int32_t longofs = arg;
+    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",
@@ -7699,9 +8143,9 @@
             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.
+      /* 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)
@@ -7742,31 +8186,31 @@
         CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
       )
       VMCASE(OP_STARTSTR,
-        uint32_t len = d->top->end_ofs - offset(d);
+        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.
+          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 > d->top->end_ofs - offset(d)) {
+          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.
+            /* 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.
+          /* We aren't finished with this string yet. */
+          d->pc--;  /* Repeat OP_STRING. */
           if (n > 0) checkpoint(d);
           return upb_pbdecoder_suspend(d);
         }
@@ -7794,8 +8238,9 @@
         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.
+        /* 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;
@@ -7812,8 +8257,9 @@
         d->pc += longofs;
       )
       VMCASE(OP_TAG1,
+        uint8_t expected;
         CHECK_SUSPEND(curbufleft(d) > 0);
-        uint8_t expected = (arg >> 8) & 0xff;
+        expected = (arg >> 8) & 0xff;
         if (*d->ptr == expected) {
           advance(d, 1);
         } else {
@@ -7824,13 +8270,14 @@
             CHECK_RETURN(dispatch(d));
           } else {
             d->pc += shortofs;
-            break; // Avoid checkpoint().
+            break; /* Avoid checkpoint(). */
           }
         }
       )
       VMCASE(OP_TAG2,
+        uint16_t expected;
         CHECK_SUSPEND(curbufleft(d) > 0);
-        uint16_t expected = (arg >> 8) & 0xffff;
+        expected = (arg >> 8) & 0xffff;
         if (curbufleft(d) >= 2) {
           uint16_t actual;
           memcpy(&actual, d->ptr, 2);
@@ -7847,9 +8294,10 @@
       )
       VMCASE(OP_TAGN, {
         uint64_t expected;
+        int32_t result;
         memcpy(&expected, d->pc, 8);
         d->pc += 2;
-        int32_t result = upb_pbdecoder_checktag_slow(d, expected);
+        result = upb_pbdecoder_checktag_slow(d, expected);
         if (result == DECODE_MISMATCH) goto badtag;
         if (result >= 0) return result;
       })
@@ -7857,34 +8305,51 @@
         CHECK_RETURN(dispatch(d));
       })
       VMCASE(OP_HALT, {
-        return size;
+        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);
-  upb_pbdecoder *d = closure;
+  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");
+    seterr(d, "Unexpected EOF: decoder still has buffered unparsed data");
+    return false;
+  }
+
+  if (d->skip) {
+    seterr(d, "Unexpected EOF inside skipped data");
     return false;
   }
 
@@ -7893,163 +8358,275 @@
     return false;
   }
 
-  // Message ends here.
-  uint64_t end = offset(d);
+  /* The user's end() call indicates that the message ends here. */
+  end = offset(d);
   d->top->end_ofs = end;
 
-  char dummy;
 #ifdef UPB_USE_JIT_X64
-  const mgroup *group = (const mgroup*)method->group;
-  if (group->jit_code) {
+  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 {
+  } else
 #endif
-    d->stack->end_ofs = end;
+  {
     const uint32_t *p = d->pc;
-    // Check the previous bytecode, but guard against beginning.
+    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.
+      /* 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));
+             getop(*d->pc) == OP_DISPATCH);
       d->pc = p;
     }
     upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL);
-#ifdef UPB_USE_JIT_X64
   }
-#endif
 
   if (d->call_len != 0) {
-    seterr(d, "Unexpected EOF");
+    seterr(d, "Unexpected EOF inside submessage or group");
     return false;
   }
 
   return true;
 }
 
-void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *m,
-                        upb_status *s) {
-  d->limit = &d->stack[UPB_DECODER_MAX_NESTING];
-  upb_bytessink_reset(&d->input_, &m->input_handler_, d);
-  d->method_ = m;
-  d->callstack[0] = &halt;
-  d->status = s;
-  upb_pbdecoder_reset(d);
+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->end_ofs = UINT64_MAX;
   d->top->groupnum = 0;
-  d->bufstart_ofs = 0;
   d->ptr = d->residual;
   d->buf = d->residual;
   d->end = d->residual;
   d->residual_end = d->residual;
-  d->call_len = 1;
+}
+
+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);
 }
 
-// Not currently required, but to support outgrowing the static stack we need
-// this.
-void upb_pbdecoder_uninit(upb_pbdecoder *d) {
-  UPB_UNUSED(d);
-}
-
 const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
   return d->method_;
 }
 
-bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink* sink) {
-  // TODO(haberman): do we need to test whether the decoder is already on the
-  // stack (like calling this from within a callback)?  Should we support
-  // rebinding the output at all?
-  assert(sink);
-  if (d->method_->dest_handlers_) {
-    if (sink->handlers != d->method_->dest_handlers_)
-      return false;
-  }
-  upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
-  return true;
-}
-
 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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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 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.
+/* Low-level functions for interacting with the output buffer. */
 
-// TODO(haberman): handle pushback
+/* 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);
@@ -8059,28 +8636,27 @@
   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.
+/* 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 ((e->limit - e->ptr) < 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;
     }
 
-    char *realloc_from = (e->buf == e->initbuf) ? NULL : e->buf;
-    char *new_buf = realloc(realloc_from, new_size);
+    new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size);
 
     if (new_buf == NULL) {
       return false;
     }
 
-    if (realloc_from == NULL) {
-      memcpy(new_buf, e->initbuf, old_size);
-    }
-
     e->ptr = new_buf + (e->ptr - e->buf);
     e->runbegin = new_buf + (e->runbegin - e->buf);
     e->limit = new_buf + new_size;
@@ -8090,22 +8666,22 @@
   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.
+/* 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((e->limit - e->ptr) >= 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.
+/* 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.
+    /* 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;
   }
@@ -8113,7 +8689,7 @@
   return true;
 }
 
-// Writes the given bytes to the buffer, handling reserve/advance.
+/* 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;
@@ -8124,52 +8700,49 @@
   return true;
 }
 
-// Finish the current run by adding the run totals to the segment and message
-// length.
+/* 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);
-  size_t run_len = 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.
+/* 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.
+    /* 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?
+      /* TODO(haberman): grow stack? */
       return false;
     }
 
     if (++e->segptr == e->seglimit) {
-      upb_pb_encoder_segment *realloc_from =
-          (e->segbuf == e->seginitbuf) ? NULL : e->segbuf;
+      /* 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 = realloc(realloc_from, new_size);
+      upb_pb_encoder_segment *new_buf =
+          upb_env_realloc(e->env, e->segbuf, old_size, new_size);
 
       if (new_buf == NULL) {
         return false;
       }
 
-      if (realloc_from == NULL) {
-        memcpy(new_buf, e->seginitbuf, old_size);
-      }
-
       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.
+    /* We were previously at the top level, start buffering. */
     e->segptr = e->segbuf;
     e->top = e->stack;
     e->runbegin = e->ptr;
@@ -8182,15 +8755,16 @@
   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.
+/* 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);
-  size_t msglen = top(e)->msglen;
+  msglen = top(e)->msglen;
 
   if (e->top == e->stack) {
-    // All lengths are now available, emit all buffered data.
+    /* 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;
@@ -8204,7 +8778,8 @@
     e->ptr = e->buf;
     e->top = NULL;
   } else {
-    // Need to keep buffering; propagate length info into enclosing submessages.
+    /* Need to keep buffering; propagate length info into enclosing
+     * submessages. */
     --e->top;
     top(e)->msglen += msglen + upb_varint_size(msglen);
   }
@@ -8215,14 +8790,14 @@
 
 /* tag_t **********************************************************************/
 
-// A precomputed (pre-encoded) tag and length.
+/* 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.
+/* 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);
@@ -8243,12 +8818,12 @@
 /* encoding of wire types *****************************************************/
 
 static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) {
-  // TODO(haberman): byte-swap for big endian.
+  /* 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.
+  /* TODO(haberman): byte-swap for big endian. */
   return encode_bytes(e, &val, sizeof(uint32_t));
 }
 
@@ -8335,19 +8910,19 @@
   }
 
 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);
+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
 
@@ -8355,13 +8930,15 @@
 /* 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);
 
-  const upb_msgdef *m = upb_handlers_msgdef(h);
-  upb_msg_field_iter i;
+  m = upb_handlers_msgdef(h);
   for(upb_msg_field_begin(&i, m);
       !upb_msg_field_done(&i);
       upb_msg_field_next(&i)) {
@@ -8373,7 +8950,7 @@
         packed ? UPB_WIRE_TYPE_DELIMITED
                : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
 
-    // Pre-encode the tag for this field.
+    /* Pre-encode the tag for this field. */
     new_tag(h, f, wt, &attr);
 
     if (packed) {
@@ -8416,7 +8993,7 @@
         upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
         break;
       case UPB_DESCRIPTOR_TYPE_GROUP: {
-        // Endgroup takes a different tag (wire_type = END_GROUP).
+        /* Endgroup takes a different tag (wire_type = END_GROUP). */
         upb_handlerattr attr2;
         new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
 
@@ -8434,6 +9011,12 @@
   }
 }
 
+void upb_pb_encoder_reset(upb_pb_encoder *e) {
+  e->segptr = NULL;
+  e->top = NULL;
+  e->depth = 0;
+}
+
 
 /* public API *****************************************************************/
 
@@ -8442,49 +9025,45 @@
   return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL);
 }
 
-#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
+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
 
-void upb_pb_encoder_init(upb_pb_encoder *e, const upb_handlers *h) {
-  e->output_ = NULL;
-  e->subc = NULL;
-  e->buf = e->initbuf;
-  e->ptr = e->buf;
-  e->limit = e->buf + ARRAYSIZE(e->initbuf);
-  e->segbuf = e->seginitbuf;
-  e->seglimit = e->segbuf + ARRAYSIZE(e->seginitbuf);
-  e->stacklimit = e->stack + ARRAYSIZE(e->stack);
-  upb_sink_reset(&e->input_, h, e);
-}
+  upb_pb_encoder *e = upb_env_malloc(env, sizeof(upb_pb_encoder));
+  if (!e) return NULL;
 
-void upb_pb_encoder_uninit(upb_pb_encoder *e) {
-  if (e->buf != e->initbuf) {
-    free(e->buf);
+  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;
   }
 
-  if (e->segbuf != e->seginitbuf) {
-    free(e->segbuf);
-  }
-}
+  e->limit = e->buf + initial_bufsize;
+  e->seglimit = e->segbuf + initial_segbufsize;
+  e->stacklimit = e->stack + stack_size;
 
-void upb_pb_encoder_resetoutput(upb_pb_encoder *e, upb_bytessink *output) {
   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;
 
-void upb_pb_encoder_reset(upb_pb_encoder *e) {
-  e->segptr = NULL;
-  e->top = NULL;
-  e->depth = 0;
+  /* 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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2010-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
 
 
 #include <stdio.h>
@@ -8493,33 +9072,36 @@
 
 upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
                                         void *owner, upb_status *status) {
-  // Create handlers.
+  /* Create handlers. */
+  const upb_pbdecodermethod *decoder_m;
   const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
+  upb_env env;
   upb_pbdecodermethodopts opts;
-  upb_pbdecodermethodopts_init(&opts, reader_h);
-  const upb_pbdecodermethod *decoder_m =
-      upb_pbdecodermethod_new(&opts, &decoder_m);
-
-  upb_pbdecoder decoder;
-  upb_descreader reader;
-
-  upb_pbdecoder_init(&decoder, decoder_m, status);
-  upb_descreader_init(&reader, reader_h, status);
-  upb_pbdecoder_resetoutput(&decoder, upb_descreader_input(&reader));
-
-  // Push input data.
-  bool ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(&decoder));
-
+  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;
-  upb_def **defs = upb_descreader_getdefs(&reader, owner, n);
+  defs = upb_descreader_getdefs(reader, owner, n);
   ret = malloc(sizeof(upb_def*) * (*n));
   memcpy(ret, defs, sizeof(upb_def*) * (*n));
 
 cleanup:
-  upb_pbdecoder_uninit(&decoder);
-  upb_descreader_uninit(&reader);
+  upb_env_uninit(&env);
   upb_handlers_unref(reader_h, &reader_h);
   upb_pbdecodermethod_unref(decoder_m, &decoder_m);
   return ret;
@@ -8528,21 +9110,24 @@
 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;
-  bool success = upb_symtab_add(s, defs, n, &defs, status);
+  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;
-  long size = ftell(f);
+  size = ftell(f);
   if(size < 0) goto error;
   if(fseek(f, 0, SEEK_SET) != 0) goto error;
-  char *buf = malloc(size + 1);
+  buf = malloc(size + 1);
   if(size && fread(buf, size, 1, f) != 1) goto error;
   fclose(f);
   if (len) *len = size;
@@ -8556,20 +9141,18 @@
 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;
   }
-  bool success = upb_load_descriptor_into_symtab(symtab, data, len, status);
+  success = upb_load_descriptor_into_symtab(symtab, data, len, status);
   free(data);
   return success;
 }
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
+ * 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.
@@ -8579,11 +9162,20 @@
 #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) {
@@ -8607,22 +9199,24 @@
 
 static int putescaped(upb_textprinter *p, const char *buf, size_t len,
                       bool preserve_utf8) {
-  // Based on CEscapeInternal() from Google's protobuf release.
+  /* 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.
+  /* 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
+  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;
     }
 
-    bool is_hex_escape = false;
+    is_hex_escape = false;
     switch (*buf) {
       case '\n': *(dst++) = '\\'; *(dst++) = 'n';  break;
       case '\r': *(dst++) = '\\'; *(dst++) = 'r';  break;
@@ -8631,9 +9225,9 @@
       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.
+        /* 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);
@@ -8645,29 +9239,34 @@
     }
     last_hex_escape = is_hex_escape;
   }
-  // Flush remaining data.
+  /* 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.
-  va_list args_copy;
-  va_copy(args_copy, args);
-  int len = vsnprintf(NULL, 0, fmt, args_copy);
+  /* 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 (vsnprintf() requires it even if we don't).
-  char *str = malloc(len + 1);
+  /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */
+  str = malloc(len + 1);
   if (!str) return false;
-  int written = vsnprintf(str, len + 1, fmt, args);
+  written = vsprintf(str, fmt, args);
   va_end(args);
   UPB_ASSERT_VAR(written, written == len);
 
-  bool ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
+  ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
   free(str);
   return ok;
 }
@@ -8676,8 +9275,8 @@
 /* handlers *******************************************************************/
 
 static bool textprinter_startmsg(void *c, const void *hd) {
-  UPB_UNUSED(hd);
   upb_textprinter *p = c;
+  UPB_UNUSED(hd);
   if (p->indent_depth_ == 0) {
     upb_bytessink_start(p->output_, 0, &p->subc);
   }
@@ -8685,9 +9284,9 @@
 }
 
 static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) {
+  upb_textprinter *p = c;
   UPB_UNUSED(hd);
   UPB_UNUSED(s);
-  upb_textprinter *p = c;
   if (p->indent_depth_ == 0) {
     upb_bytessink_end(p->output_);
   }
@@ -8724,14 +9323,14 @@
 
 TYPE(int32,  int32_t,  "%" PRId32)
 TYPE(int64,  int64_t,  "%" PRId64)
-TYPE(uint32, uint32_t, "%" PRIu32);
+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.
+/* 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;
@@ -8751,17 +9350,17 @@
 
 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);
-  upb_textprinter *p = closure;
   indent(p);
   putf(p, "%s: \"", upb_fielddef_name(f));
   return p;
 }
 
 static bool textprinter_endstr(void *closure, const void *handler_data) {
-  UPB_UNUSED(handler_data);
   upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
   putf(p, "\"");
   endfield(p);
   return true;
@@ -8769,9 +9368,9 @@
 
 static size_t textprinter_putstr(void *closure, const void *hd, const char *buf,
                                  size_t len, const upb_bufhandle *handle) {
-  UPB_UNUSED(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:
@@ -8790,8 +9389,8 @@
 }
 
 static bool textprinter_endsubmsg(void *closure, const void *handler_data) {
-  UPB_UNUSED(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);
@@ -8801,32 +9400,14 @@
   return false;
 }
 
-
-/* Public API *****************************************************************/
-
-void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h) {
-  p->single_line_ = false;
-  p->indent_depth_ = 0;
-  upb_sink_reset(&p->input_, h, p);
-}
-
-void upb_textprinter_uninit(upb_textprinter *p) {
-  UPB_UNUSED(p);
-}
-
-void upb_textprinter_reset(upb_textprinter *p, bool single_line) {
-  p->single_line_ = single_line;
-  p->indent_depth_ = 0;
-}
-
 static void onmreg(const void *c, upb_handlers *h) {
-  UPB_UNUSED(c);
   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);
 
-  upb_msg_field_iter i;
   for(upb_msg_field_begin(&i, m);
       !upb_msg_field_done(&i);
       upb_msg_field_next(&i)) {
@@ -8878,6 +9459,26 @@
   }
 }
 
+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);
@@ -8885,48 +9486,38 @@
 
 upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; }
 
-bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output) {
-  p->output_ = output;
-  return true;
-}
-
 void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
   p->single_line_ = single_line;
 }
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
 
 
-// Index is descriptor type.
+/* 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
+  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).
+/* 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;
@@ -8950,7 +9541,7 @@
   return r;
 }
 
-// Like the previous, but uses 64-bit values.
+/* 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;
@@ -8972,77 +9563,78 @@
   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.
+/* 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.
+/* 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));
-  uint64_t stop_bit = upb_get_vstopbit(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.
+    /* Error: unterminated varint. */
     upb_decoderet err_r = {(void*)0, 0};
     return err_r;
   }
-  upb_decoderet my_r = {r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
-                        r.val | (b << 7)};
+  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.
+/* 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));
-  uint64_t stop_bit = upb_get_vstopbit(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.
+    /* Error: unterminated varint. */
     upb_decoderet err_r = {(void*)0, 0};
     return err_r;
   }
-  upb_decoderet my_r = {r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
-                        r.val | (b << 14)};
+  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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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>
@@ -9052,9 +9644,74 @@
 #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.
+/* Used to signal that a capture has been suspended. */
 static char suspend_capture;
 
 static upb_selector_t getsel_for_handlertype(upb_json_parser *p,
@@ -9072,15 +9729,16 @@
 
 static bool check_stack(upb_json_parser *p) {
   if ((p->top + 1) == p->limit) {
-    upb_status_seterrmsg(p->status, "Nesting too deep");
+    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.
+/* 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;
@@ -9089,7 +9747,7 @@
 }
 
 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 is unsigned, so this is defined behavior even on overflow. */
   size_t ret = a * b;
   if (b != 0 && ret / b != a) {
     ret = SIZE_MAX;
@@ -9100,7 +9758,7 @@
 
 /* Base64 decoding ************************************************************/
 
-// TODO(haberman): make this streaming.
+/* TODO(haberman): make this streaming. */
 
 static const signed char b64table[] = {
   -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
@@ -9137,37 +9795,40 @@
   -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).
+/* 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.
+/* 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,
+      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;
     }
 
-    uint32_t val = b64lookup(ptr[0]) << 18 |
-                   b64lookup(ptr[1]) << 12 |
-                   b64lookup(ptr[2]) << 6  |
-                   b64lookup(ptr[3]);
+    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.
+    /* Test the upper bit; returns true if any of the characters returned -1. */
     if (val & 0x80000000) {
       goto otherchar;
     }
 
-    char output[3];
     output[0] = val >> 16;
     output[1] = (val >> 8) & 0xff;
     output[2] = val & 0xff;
@@ -9178,34 +9839,40 @@
 otherchar:
   if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) ||
       nonbase64(ptr[3]) ) {
-    upb_status_seterrf(p->status,
+    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] == '=') {
-    // Last group contains only two input bytes, one output byte.
+    uint32_t val;
+    char output;
+
+    /* Last group contains only two input bytes, one output byte. */
     if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') {
       goto badpadding;
     }
 
-    uint32_t val = b64lookup(ptr[0]) << 18 |
-                   b64lookup(ptr[1]) << 12;
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12;
 
     assert(!(val & 0x80000000));
-    char output = val >> 16;
+    output = val >> 16;
     upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL);
     return true;
   } else {
-    // Last group contains only three input bytes, two output bytes.
+    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;
     }
 
-    uint32_t val = b64lookup(ptr[0]) << 18 |
-                   b64lookup(ptr[1]) << 12 |
-                   b64lookup(ptr[2]) << 6;
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6;
 
-    char output[2];
     output[0] = val >> 16;
     output[1] = (val >> 8) & 0xff;
     upb_sink_putstring(&p->top->sink, sel, output, 2, NULL);
@@ -9213,33 +9880,34 @@
   }
 
 badpadding:
-  upb_status_seterrf(p->status,
+  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.
+/* 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);
@@ -9252,16 +9920,19 @@
   p->accumulated_len = 0;
 }
 
-// Used internally by accumulate_append().
+/* Used internally by accumulate_append(). */
 static bool accumulate_realloc(upb_json_parser *p, size_t need) {
-  size_t new_size = UPB_MAX(p->accumulate_buf_size, 128);
+  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);
   }
 
-  void *mem = realloc(p->accumulate_buf, new_size);
+  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_status_seterrmsg(&p->status, "Out of memory allocating buffer.");
+    upb_env_reporterror(p->env, &p->status);
     return false;
   }
 
@@ -9270,20 +9941,22 @@
   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).
+/* 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;
   }
 
-  size_t need;
   if (!checked_add(p->accumulated_len, len, &need)) {
-    upb_status_seterrmsg(p->status, "Integer overflow.");
+    upb_status_seterrmsg(&p->status, "Integer overflow.");
+    upb_env_reporterror(p->env, &p->status);
     return false;
   }
 
@@ -9301,9 +9974,9 @@
   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.
+/* 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;
@@ -9313,42 +9986,42 @@
 
 /* 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).
+/* 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.
+/* This is the set of states for p->multipart_state. */
 enum {
-  // We are not currently processing multipart data.
+  /* We are not currently processing multipart data. */
   MULTIPART_INACTIVE = 0,
 
-  // We are processing multipart data by accumulating it into a contiguous
-  // buffer.
+  /* 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.
+  /* 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.
+/* 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.
+/* 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);
@@ -9361,7 +10034,8 @@
   switch (p->multipart_state) {
     case MULTIPART_INACTIVE:
       upb_status_seterrmsg(
-          p->status, "Internal error: unexpected state MULTIPART_INACTIVE");
+          &p->status, "Internal error: unexpected state MULTIPART_INACTIVE");
+      upb_env_reporterror(p->env, &p->status);
       return false;
 
     case MULTIPART_ACCUMULATE:
@@ -9380,8 +10054,8 @@
   return true;
 }
 
-// Note: this invalidates the accumulate buffer!  Call only after reading its
-// contents.
+/* 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;
@@ -9391,9 +10065,9 @@
 
 /* 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.
+/* 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);
@@ -9411,24 +10085,24 @@
   }
 }
 
-// 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.
+/* 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).
+    /* 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.
+    /* Need to back up the pointer to the beginning of the capture, since
+     * we were not able to actually preserve it. */
     *ptr = p->capture;
   }
 }
@@ -9443,8 +10117,8 @@
 
 /* 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.
+/* 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) {
@@ -9489,8 +10163,8 @@
 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.
+  /* 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;
@@ -9508,8 +10182,8 @@
     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).
+  /* 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);
 }
@@ -9538,17 +10212,29 @@
 }
 
 static bool parse_number(upb_json_parser *p) {
-  // 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.
+  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;
   }
 
-  size_t len;
-  const char *buf = accumulate_getptr(p, &len);
-  const char *myend = buf + len - 1;  // One for NULL.
+  buf = accumulate_getptr(p, &len);
+  myend = buf + len - 1;  /* One for NULL. */
 
-  char *end;
+  /* 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: {
@@ -9560,7 +10246,7 @@
       break;
     }
     case UPB_TYPE_INT64: {
-      long long val = strtoll(p->accumulated, &end, 0);
+      long long val = strtol(p->accumulated, &end, 0);
       if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend)
         goto err;
       else
@@ -9576,7 +10262,7 @@
       break;
     }
     case UPB_TYPE_UINT64: {
-      unsigned long long val = strtoull(p->accumulated, &end, 0);
+      unsigned long long val = strtoul(p->accumulated, &end, 0);
       if (val > UINT64_MAX || errno == ERANGE || end != myend)
         goto err;
       else
@@ -9592,7 +10278,7 @@
       break;
     }
     case UPB_TYPE_FLOAT: {
-      float val = strtof(p->accumulated, &end);
+      float val = strtod(p->accumulated, &end);
       if (errno == ERANGE || end != myend)
         goto err;
       else
@@ -9608,20 +10294,24 @@
   return true;
 
 err:
-  upb_status_seterrf(p->status, "error parsing number: %s", buf);
+  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,
+    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;
   }
 
-  bool ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val);
+  ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val);
   UPB_ASSERT_VAR(ok, ok);
 
   return true;
@@ -9631,12 +10321,15 @@
   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.
-    upb_jsonparser_frame *inner = p->top + 1;
-    upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+    /* 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;
@@ -9645,11 +10338,11 @@
     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.
+      /* 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 {
@@ -9657,17 +10350,18 @@
       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.
+    /* 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,
+    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;
   }
 }
@@ -9681,7 +10375,7 @@
                        p->accumulated, p->accumulated_len)) {
         return false;
       }
-      // Fall through.
+      /* Fall through. */
 
     case UPB_TYPE_STRING: {
       upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
@@ -9691,7 +10385,7 @@
     }
 
     case UPB_TYPE_ENUM: {
-      // Resolve enum symbolic name to integer value.
+      /* Resolve enum symbolic name to integer value. */
       const upb_enumdef *enumdef =
           (const upb_enumdef*)upb_fielddef_subdef(p->top->f);
 
@@ -9705,7 +10399,8 @@
         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_status_seterrf(&p->status, "Enum value unknown: '%.*s'", len, buf);
+        upb_env_reporterror(p->env, &p->status);
       }
 
       break;
@@ -9713,7 +10408,8 @@
 
     default:
       assert(false);
-      upb_status_seterrmsg(p->status, "Internal error in JSON decoder");
+      upb_status_seterrmsg(&p->status, "Internal error in JSON decoder");
+      upb_env_reporterror(p->env, &p->status);
       ok = false;
       break;
   }
@@ -9728,22 +10424,23 @@
   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.
+/* 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.
+  /* 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_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)) {
@@ -9751,7 +10448,7 @@
     case UPB_TYPE_INT64:
     case UPB_TYPE_UINT32:
     case UPB_TYPE_UINT64:
-      // Invoke end_number. The accum buffer has the number's text already.
+      /* Invoke end_number. The accum buffer has the number's text already. */
       if (!parse_number(p)) {
         return false;
       }
@@ -9766,8 +10463,9 @@
           return false;
         }
       } else {
-        upb_status_seterrmsg(p->status,
+        upb_status_seterrmsg(&p->status,
                              "Map bool key not 'true' or 'false'");
+        upb_env_reporterror(p->env, &p->status);
         return false;
       }
       multipart_end(p);
@@ -9785,57 +10483,64 @@
       break;
     }
     default:
-      upb_status_seterrmsg(p->status, "Invalid field type for map key");
+      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.
+/* 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) {
-  // 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.
+  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;
 
-  const upb_fielddef *mapfield = p->top->mapfield;
-  const upb_msgdef *mapentrymsg = upb_fielddef_msgsubdef(mapfield);
+  mapfield = p->top->mapfield;
+  mapentrymsg = upb_fielddef_msgsubdef(mapfield);
 
-  upb_jsonparser_frame *inner = p->top + 1;
+  inner = p->top + 1;
   p->top->f = mapfield;
-  upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+  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).
+  /* 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.
+  /* 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.
+  /* 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->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_status_seterrmsg(&p->status, "mapentry message has no value");
+    upb_env_reporterror(p->env, &p->status);
     return false;
   }
 
@@ -9853,8 +10558,10 @@
     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);
+      /* 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;
     }
 
@@ -9866,19 +10573,21 @@
 }
 
 static void end_member(upb_json_parser *p) {
-  // If we just parsed a map-entry value, end that frame too.
+  /* If we just parsed a map-entry value, end that frame too. */
   if (p->top->is_mapentry) {
-    assert(p->top > p->stack);
-    // send ENDMSG on submsg.
     upb_status s = UPB_STATUS_INIT;
-    upb_sink_endmsg(&p->top->sink, &s);
-    const upb_fielddef* mapfield = p->top->mapfield;
-
-    // send ENDSUBMSG in repeated-field-of-mapentries frame.
-    p->top--;
     upb_selector_t sel;
-    bool ok = upb_handlers_getselector(mapfield,
-                                       UPB_HANDLER_ENDSUBMSG, &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);
   }
@@ -9890,12 +10599,15 @@
   assert(p->top->f);
 
   if (upb_fielddef_ismap(p->top->f)) {
-    // Beginning of a map. Start a new parser frame in a repeated-field
-    // context.
+    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;
 
-    upb_jsonparser_frame *inner = p->top + 1;
-    upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+    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;
@@ -9906,13 +10618,16 @@
 
     return true;
   } else if (upb_fielddef_issubmsg(p->top->f)) {
-    // Beginning of a subobject. Start a new parser frame in the submsg
-    // context.
+    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;
 
-    upb_jsonparser_frame *inner = p->top + 1;
+    inner = p->top + 1;
 
-    upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+    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;
@@ -9922,39 +10637,46 @@
 
     return true;
   } else {
-    upb_status_seterrf(p->status,
+    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--;
-    upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
     upb_sink_endseq(&p->top->sink, sel);
   } else {
+    upb_selector_t sel;
     p->top--;
-    upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+    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,
+    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;
 
-  upb_jsonparser_frame *inner = p->top + 1;
-  upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+  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;
@@ -9966,10 +10688,12 @@
 }
 
 static void end_array(upb_json_parser *p) {
+  upb_selector_t sel;
+
   assert(p->top > p->stack);
 
   p->top--;
-  upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+  sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
   upb_sink_endseq(&p->top->sink, sel);
 }
 
@@ -9982,7 +10706,11 @@
 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);
+    }
   }
 }
 
@@ -9992,27 +10720,27 @@
 
 /* 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.
+/* 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 1085 "upb/json/parser.rl"
+#line 1218 "upb/json/parser.rl"
 
 
 
-#line 997 "upb/json/parser.c"
+#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, 
@@ -10154,8 +10882,6 @@
 };
 
 static const int json_start = 1;
-static const int json_first_final = 56;
-static const int json_error = 0;
 
 static const int json_en_number_machine = 10;
 static const int json_en_string_machine = 19;
@@ -10163,16 +10889,13 @@
 static const int json_en_main = 1;
 
 
-#line 1088 "upb/json/parser.rl"
+#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_UNUSED(hd);
-  UPB_UNUSED(handle);
   upb_json_parser *parser = closure;
-  parser->handle = handle;
 
-  // Variables used by Ragel's generated code.
+  /* Variables used by Ragel's generated code. */
   int cs = parser->current_state;
   int *stack = parser->parser_stack;
   int top = parser->parser_top;
@@ -10180,10 +10903,15 @@
   const char *p = buf;
   const char *pe = buf + size;
 
+  parser->handle = handle;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
   capture_resume(parser, buf);
 
   
-#line 1168 "upb/json/parser.c"
+#line 1301 "upb/json/parser.c"
 	{
 	int _klen;
 	unsigned int _trans;
@@ -10258,118 +10986,118 @@
 		switch ( *_acts++ )
 		{
 	case 0:
-#line 1000 "upb/json/parser.rl"
+#line 1133 "upb/json/parser.rl"
 	{ p--; {cs = stack[--top]; goto _again;} }
 	break;
 	case 1:
-#line 1001 "upb/json/parser.rl"
+#line 1134 "upb/json/parser.rl"
 	{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
 	break;
 	case 2:
-#line 1005 "upb/json/parser.rl"
+#line 1138 "upb/json/parser.rl"
 	{ start_text(parser, p); }
 	break;
 	case 3:
-#line 1006 "upb/json/parser.rl"
+#line 1139 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_text(parser, p)); }
 	break;
 	case 4:
-#line 1012 "upb/json/parser.rl"
+#line 1145 "upb/json/parser.rl"
 	{ start_hex(parser); }
 	break;
 	case 5:
-#line 1013 "upb/json/parser.rl"
+#line 1146 "upb/json/parser.rl"
 	{ hexdigit(parser, p); }
 	break;
 	case 6:
-#line 1014 "upb/json/parser.rl"
+#line 1147 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_hex(parser)); }
 	break;
 	case 7:
-#line 1020 "upb/json/parser.rl"
+#line 1153 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(escape(parser, p)); }
 	break;
 	case 8:
-#line 1026 "upb/json/parser.rl"
+#line 1159 "upb/json/parser.rl"
 	{ p--; {cs = stack[--top]; goto _again;} }
 	break;
 	case 9:
-#line 1029 "upb/json/parser.rl"
+#line 1162 "upb/json/parser.rl"
 	{ {stack[top++] = cs; cs = 19; goto _again;} }
 	break;
 	case 10:
-#line 1031 "upb/json/parser.rl"
+#line 1164 "upb/json/parser.rl"
 	{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
 	break;
 	case 11:
-#line 1036 "upb/json/parser.rl"
+#line 1169 "upb/json/parser.rl"
 	{ start_member(parser); }
 	break;
 	case 12:
-#line 1037 "upb/json/parser.rl"
+#line 1170 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_membername(parser)); }
 	break;
 	case 13:
-#line 1040 "upb/json/parser.rl"
+#line 1173 "upb/json/parser.rl"
 	{ end_member(parser); }
 	break;
 	case 14:
-#line 1046 "upb/json/parser.rl"
+#line 1179 "upb/json/parser.rl"
 	{ start_object(parser); }
 	break;
 	case 15:
-#line 1049 "upb/json/parser.rl"
+#line 1182 "upb/json/parser.rl"
 	{ end_object(parser); }
 	break;
 	case 16:
-#line 1055 "upb/json/parser.rl"
+#line 1188 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(start_array(parser)); }
 	break;
 	case 17:
-#line 1059 "upb/json/parser.rl"
+#line 1192 "upb/json/parser.rl"
 	{ end_array(parser); }
 	break;
 	case 18:
-#line 1064 "upb/json/parser.rl"
+#line 1197 "upb/json/parser.rl"
 	{ start_number(parser, p); }
 	break;
 	case 19:
-#line 1065 "upb/json/parser.rl"
+#line 1198 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_number(parser, p)); }
 	break;
 	case 20:
-#line 1067 "upb/json/parser.rl"
+#line 1200 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(start_stringval(parser)); }
 	break;
 	case 21:
-#line 1068 "upb/json/parser.rl"
+#line 1201 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_stringval(parser)); }
 	break;
 	case 22:
-#line 1070 "upb/json/parser.rl"
+#line 1203 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
 	break;
 	case 23:
-#line 1072 "upb/json/parser.rl"
+#line 1205 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
 	break;
 	case 24:
-#line 1074 "upb/json/parser.rl"
+#line 1207 "upb/json/parser.rl"
 	{ /* null value */ }
 	break;
 	case 25:
-#line 1076 "upb/json/parser.rl"
+#line 1209 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(start_subobject(parser)); }
 	break;
 	case 26:
-#line 1077 "upb/json/parser.rl"
+#line 1210 "upb/json/parser.rl"
 	{ end_subobject(parser); }
 	break;
 	case 27:
-#line 1082 "upb/json/parser.rl"
+#line 1215 "upb/json/parser.rl"
 	{ p--; {cs = stack[--top]; goto _again;} }
 	break;
-#line 1354 "upb/json/parser.c"
+#line 1487 "upb/json/parser.c"
 		}
 	}
 
@@ -10382,16 +11110,17 @@
 	_out: {}
 	}
 
-#line 1107 "upb/json/parser.rl"
+#line 1242 "upb/json/parser.rl"
 
   if (p != pe) {
-    upb_status_seterrf(parser->status, "Parse error at %s\n", p);
+    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.
+  /* Save parsing state back to parser. */
   parser->current_state = cs;
   parser->parser_top = top;
 
@@ -10401,13 +11130,54 @@
 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 *****************************************************************/
 
-void upb_json_parser_init(upb_json_parser *p, upb_status *status) {
+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;
@@ -10415,57 +11185,24 @@
   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);
-  p->status = status;
-}
 
-void upb_json_parser_uninit(upb_json_parser *p) {
-  upb_byteshandler_uninit(&p->input_handler_);
-  free(p->accumulate_buf);
-}
+  json_parser_reset(p);
+  upb_sink_reset(&p->top->sink, output->handlers, output->closure);
+  p->top->m = upb_handlers_msgdef(output->handlers);
 
-void upb_json_parser_reset(upb_json_parser *p) {
-  p->top = p->stack;
-  p->top->f = NULL;
-  p->top->is_map = false;
-  p->top->is_mapentry = false;
-
-  int cs;
-  int top;
-  // Emit Ragel initialization of the parser.
-  
-#line 1418 "upb/json/parser.c"
-	{
-	cs = json_start;
-	top = 0;
-	}
-
-#line 1157 "upb/json/parser.rl"
-  p->current_state = cs;
-  p->parser_top = top;
-  accumulate_clear(p);
-  p->multipart_state = MULTIPART_INACTIVE;
-  p->capture = NULL;
-}
-
-void upb_json_parser_resetoutput(upb_json_parser *p, upb_sink *sink) {
-  upb_json_parser_reset(p);
-  upb_sink_reset(&p->top->sink, sink->handlers, sink->closure);
-  p->top->m = upb_handlers_msgdef(sink->handlers);
-  p->accumulated = NULL;
+  /* 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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * This currently uses snprintf() to format primitives, and could be optimized
- * further.
- */
+** This currently uses snprintf() to format primitives, and could be optimized
+** further.
+*/
 
 
 #include <stdlib.h>
@@ -10473,7 +11210,28 @@
 #include <string.h>
 #include <stdint.h>
 
-// StringPiece; a pointer plus a length.
+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;
@@ -10487,11 +11245,11 @@
   return ret;
 }
 
-// ------------ JSON string printing: values, maps, arrays --------------------
+/* ------------ 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.
+  /* 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);
 }
@@ -10503,18 +11261,18 @@
   p->first_elem_[p->depth_] = false;
 }
 
-// Helpers that print properly formatted elements to the JSON output stream.
+/* Helpers that print properly formatted elements to the JSON output stream. */
 
-// Used for escaping control chars in strings.
+/* Used for escaping control chars in strings. */
 static const char kControlCharLimit = 0x20;
 
-static inline bool is_json_escaped(char c) {
-  // See RFC 4627.
+UPB_INLINE bool is_json_escaped(char c) {
+  /* See RFC 4627. */
   unsigned char uc = (unsigned char)c;
   return uc < kControlCharLimit || uc == '"' || uc == '\\';
 }
 
-static inline char* json_nice_escape(char c) {
+UPB_INLINE char* json_nice_escape(char c) {
   switch (c) {
     case '"':  return "\\\"";
     case '\\': return "\\\\";
@@ -10527,46 +11285,47 @@
   }
 }
 
-// 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.
+/* 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;
-  for (unsigned int i = 0; i < len; i++) {
+  unsigned int i;
+  for (i = 0; i < len; i++) {
     char c = buf[i];
-    // Handle escaping.
+    /* Handle escaping. */
     if (is_json_escaped(c)) {
-      // Use a "nice" escape, like \n, if one exists for this character.
+      /* 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.
+      /* 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;
-        snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte);
+        _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.
+      /* 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 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.
+      /* Then print the escape code. */
       print_data(p, escape, strlen(escape));
     } else {
-      // Add to the current unescaped run of characters.
+      /* 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 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);
   }
@@ -10574,42 +11333,42 @@
 
 #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.
+/* 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 = snprintf(buf, length, "%.17g", val);
+  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 = snprintf(buf, length, "%.8g", val);
+  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 = snprintf(buf, length, "%s", (val ? "true" : "false"));
+  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 = snprintf(buf, length, "%ld", val);
+  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 = snprintf(buf, length, "%llu", val);
+  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.
+/* 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;
@@ -10620,15 +11379,15 @@
   return true;
 }
 
-#define CHKFMT(val) if ((val) == -1) return false;
+#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;                                           \
-    UPB_UNUSED(handler_data);                                                \
     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;                                                             \
@@ -10657,20 +11416,20 @@
     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);
+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);
+/* 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
@@ -10684,9 +11443,11 @@
                         int32_t val) {
   const EnumHandlerData *hd = handler_data;
   upb_json_printer *p = closure;
+  const char *symbolic_name;
+
   CHK(putkey(closure, hd->keyname));
 
-  const char *symbolic_name = upb_enumdef_iton(hd->enumdef, val);
+  symbolic_name = upb_enumdef_iton(hd->enumdef, val);
   if (symbolic_name) {
     print_data(p, "\"", 1);
     putstring(p, symbolic_name, strlen(symbolic_name));
@@ -10737,8 +11498,8 @@
 }
 
 static void *repeated_startsubmsg(void *closure, const void *handler_data) {
-  UPB_UNUSED(handler_data);
   upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
   print_comma(p);
   return closure;
 }
@@ -10755,8 +11516,8 @@
 }
 
 static bool printer_startmsg(void *closure, const void *handler_data) {
-  UPB_UNUSED(handler_data);
   upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
   if (p->depth_ == 0) {
     upb_bytessink_start(p->output_, 0, &p->subc_);
   }
@@ -10765,9 +11526,9 @@
 }
 
 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);
-  upb_json_printer *p = closure;
   end_frame(p);
   if (p->depth_ == 0) {
     upb_bytessink_end(p->output_);
@@ -10785,8 +11546,8 @@
 }
 
 static bool endseq(void *closure, const void *handler_data) {
-  UPB_UNUSED(handler_data);
   upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
   print_data(p, "]", 1);
   p->depth_--;
   return true;
@@ -10802,8 +11563,8 @@
 }
 
 static bool endmap(void *closure, const void *handler_data) {
-  UPB_UNUSED(handler_data);
   upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
   print_data(p, "}", 1);
   p->depth_--;
   return true;
@@ -10811,32 +11572,35 @@
 
 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);
-  upb_json_printer *p = closure;
   putstring(p, str, len);
   return len;
 }
 
-// This has to Base64 encode the bytes, because JSON has no "bytes" type.
+/* 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_UNUSED(handler_data);
-  UPB_UNUSED(handle);
   upb_json_printer *p = closure;
 
-  // This is the regular base64, not the "web-safe" version.
+  /* This is the regular base64, not the "web-safe" version. */
   static const char base64[] =
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-  // Base64-encode.
+  /* 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)
+    /* TODO(haberman): handle encoded lengths > sizeof(data) */
     UPB_ASSERT_VAR(limit, (limit - to) >= 4);
 
     to[0] = base64[from[0] >> 2];
@@ -10868,7 +11632,7 @@
       break;
   }
 
-  size_t bytes = to - data;
+  bytes = to - data;
   print_data(p, "\"", 1);
   putstring(p, data, bytes);
   print_data(p, "\"", 1);
@@ -10877,9 +11641,9 @@
 
 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);
-  upb_json_printer *p = closure;
   CHK(putkey(closure, handler_data));
   print_data(p, "\"", 1);
   return p;
@@ -10893,17 +11657,17 @@
 }
 
 static bool scalar_endstr(void *closure, const void *handler_data) {
-  UPB_UNUSED(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);
-  upb_json_printer *p = closure;
   print_comma(p);
   print_data(p, "\"", 1);
   return p;
@@ -10917,17 +11681,17 @@
 }
 
 static bool repeated_endstr(void *closure, const void *handler_data) {
-  UPB_UNUSED(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);
-  upb_json_printer *p = closure;
   print_data(p, "\"", 1);
   return p;
 }
@@ -10940,15 +11704,15 @@
 }
 
 static bool mapkey_endstr(void *closure, const void *handler_data) {
-  UPB_UNUSED(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_UNUSED(handler_data);
   upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
   print_data(p, "\"", 1);
   return true;
 }
@@ -10989,30 +11753,31 @@
   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.
+/* 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) {
-  UPB_UNUSED(closure);
   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.
+  /* 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);
@@ -11080,8 +11845,8 @@
       break;
     }
     case UPB_TYPE_MESSAGE:
-      // No handler necessary -- the submsg handlers will print the message
-      // as appropriate.
+      /* No handler necessary -- the submsg handlers will print the message
+       * as appropriate. */
       break;
   }
 
@@ -11089,14 +11854,16 @@
 }
 
 void printer_sethandlers(const void *closure, upb_handlers *h) {
-  UPB_UNUSED(closure);
   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.
+    /* mapentry messages are sufficiently different that we handle them
+     * separately. */
     printer_sethandlers_mapentry(closure, h);
     return;
   }
@@ -11113,7 +11880,6 @@
     }                                                                         \
     break;
 
-  upb_msg_field_iter i;
   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);
@@ -11138,9 +11904,9 @@
       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.
+        /* 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);
 
@@ -11165,8 +11931,8 @@
         }
         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.
+        /* 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 {
@@ -11189,25 +11955,29 @@
 #undef TYPE
 }
 
+static void json_printer_reset(upb_json_printer *p) {
+  p->depth_ = 0;
+}
+
+
 /* Public API *****************************************************************/
 
-void upb_json_printer_init(upb_json_printer *p, const upb_handlers *h) {
-  p->output_ = NULL;
-  p->depth_ = 0;
-  upb_sink_reset(&p->input_, h, p);
-}
+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
 
-void upb_json_printer_uninit(upb_json_printer *p) {
-  UPB_UNUSED(p);
-}
+  upb_json_printer *p = upb_env_malloc(e, sizeof(upb_json_printer));
+  if (!p) return NULL;
 
-void upb_json_printer_reset(upb_json_printer *p) {
-  p->depth_ = 0;
-}
-
-void upb_json_printer_resetoutput(upb_json_printer *p, upb_bytessink *output) {
-  upb_json_printer_reset(p);
   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) {
diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h
index 8f6d364..078e2a2 100644
--- a/ruby/ext/google/protobuf_c/upb.h
+++ b/ruby/ext/google/protobuf_c/upb.h
@@ -1,70 +1,62 @@
 // Amalgamated source file
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * Defs are upb's internal representation of the constructs that can appear
- * in a .proto file:
- *
- * - upb_msgdef: describes a "message" construct.
- * - upb_fielddef: describes a message field.
- * - upb_enumdef: describes an enum.
- * (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.
- */
+** 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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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_
@@ -73,16 +65,11 @@
 #include <stdint.h>
 #include <string.h>
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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_
@@ -92,22 +79,61 @@
 #include <stdbool.h>
 #include <stddef.h>
 
-// inline if possible, emit standalone code if required.
+/* 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 inline
+#define UPB_INLINE static
 #endif
 
-#if __STDC_VERSION__ >= 199901L
-#define UPB_C99
+/* 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) \
@@ -116,51 +142,53 @@
 #define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
   class_name() = delete; \
   ~class_name() = delete; \
-  /* Friend Pointer<T> so it can access base class. */ \
-  friend class Pointer<full_class_name>; \
-  friend class Pointer<const full_class_name>; \
   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)
+#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(); \
-  /* Friend Pointer<T> so it can access base class. */ \
-  friend class Pointer<full_class_name>; \
-  friend class Pointer<const full_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_PRIVATE_FOR_CPP private:
-#define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname;
 #define UPB_BEGIN_EXTERN_C extern "C" {
 #define UPB_END_EXTERN_C }
-#define UPB_DEFINE_STRUCT0(cname, members) members;
-#define UPB_DEFINE_STRUCT(cname, cbase, members) \
- public:                                         \
-  cbase* base() { return &base_; }               \
-  const cbase* base() const { return &base_; }   \
-                                                 \
- private:                                        \
-  cbase base_;                                   \
-  members;
-#define UPB_DEFINE_CLASS0(cppname, cppmethods, members) \
-  class cppname {                                      \
-    cppmethods                                         \
-    members                                            \
-  };                                                   \
-  UPB_ASSERT_STDLAYOUT(cppname);
-#define UPB_DEFINE_CLASS1(cppname, cppbase, cppmethods, members)   \
-  UPB_DEFINE_CLASS0(cppname, cppmethods, members)                  \
+#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> { \
@@ -174,8 +202,11 @@
     explicit Pointer(const cppname* ptr) : PointerBase(ptr) {}    \
   };                                                              \
   }
-#define UPB_DEFINE_CLASS2(cppname, cppbase, cppbase2, cppmethods, members)    \
-  UPB_DEFINE_CLASS0(cppname, UPB_QUOTE(cppmethods), members)                  \
+
+#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> { \
@@ -190,96 +221,97 @@
   };                                                                         \
   }
 
-#else  // !defined(__cplusplus)
+#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_BEGIN_EXTERN_C
-#define UPB_END_EXTERN_C
-#define UPB_DEFINE_STRUCT0(cname, members) \
-  struct cname {                           \
-    members;                               \
-  };
-#define UPB_DEFINE_STRUCT(cname, cbase, members) \
-  struct cname {                                 \
-    cbase base;                                  \
-    members;                                     \
-  };
-#define UPB_DEFINE_CLASS0(cppname, cppmethods, members) members
-#define UPB_DEFINE_CLASS1(cppname, cppbase, cppmethods, members) members
-#define UPB_DEFINE_CLASS2(cppname, cppbase, cppbase2, cppmethods, members) \
-  members
+#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)
-
-#ifdef __GNUC__
-#define UPB_NORETURN __attribute__((__noreturn__))
-#else
-#define UPB_NORETURN
-#endif
+#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
 
-// Code with commas confuses the preprocessor when passed as arguments, whether
-// C++ type names with commas (eg. Foo<int, int>) or code blocks that declare
-// variables (ie. int foo, bar).
-#define UPB_QUOTE(...) __VA_ARGS__
-
-// 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.
+/* 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.
+/* Generic function type. */
 typedef void upb_func();
 
-/* Casts **********************************************************************/
-
-// Upcasts for C.  For downcasts see the definitions of the subtypes.
-#define UPB_UPCAST(obj) (&(obj)->base)
-#define UPB_UPCAST2(obj) UPB_UPCAST(UPB_UPCAST(obj))
+/* C++ Casts ******************************************************************/
 
 #ifdef __cplusplus
 
-// Downcasts for C++.  We can't use C++ inheritance directly and maintain
-// compatibility with C.  So our inheritance is undeclared in C++.
-// Specializations of these casting functions are defined for appropriate type
-// pairs, and perform the necessary checks.
-//
-// Example:
-//   upb::Def* def = <...>;
-//   upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def);
-
 namespace upb {
 
-// Casts to a direct subclass.  The caller must know that cast is correct; an
-// incorrect cast will throw an assertion failure in debug mode.
-template<class To, class From> To down_cast(From* f);
-
-// Casts to a direct subclass.  If the class does not actually match the given
-// subtype, returns NULL.
-template<class To, class From> To dyn_cast(From* f);
-
-// Pointer<T> is a simple wrapper around a T*.  It is only constructed for
-// upcast() below, and its sole purpose is to be implicitly convertable to T* or
-// pointers to base classes, just as a pointer would be in regular C++ if the
-// inheritance were directly expressed as C++ inheritance.
 template <class T> class Pointer;
 
-// Casts to any base class, or the type itself (ie. can be a no-op).
+/* 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 ptr_->base(); }
+  operator Base*() { return (Base*)ptr_; }
 
  private:
   T* ptr_;
@@ -301,17 +333,17 @@
 
 #ifdef __cplusplus
 
-#include <algorithm>  // For std::swap().
+#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).
+/* 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.
+  /* 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)) {
@@ -342,8 +374,8 @@
     return *this;
   }
 
-  // TODO(haberman): add C++11 move construction/assignment for greater
-  // efficiency.
+  /* TODO(haberman): add C++11 move construction/assignment for greater
+   * efficiency. */
 
   void swap(reffed_ptr& other) {
     if (ptr_ == other.ptr_) {
@@ -367,7 +399,7 @@
 
   T* get() const { return ptr_; }
 
-  // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
+  /* 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);
@@ -383,8 +415,8 @@
     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:
+  /* 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);
@@ -396,9 +428,9 @@
   T* ptr_;
 };
 
-}  // namespace upb
+}  /* namespace upb */
 
-#endif  // __cplusplus
+#endif  /* __cplusplus */
 
 
 /* upb::Status ****************************************************************/
@@ -410,70 +442,76 @@
 }
 #endif
 
-UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace);
-UPB_DECLARE_TYPE(upb::Status, upb_status);
+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.
+/* 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.
+/* 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);
 
-UPB_DEFINE_CLASS0(upb::ErrorSpace,
-,
-UPB_DEFINE_STRUCT0(upb_errorspace,
+#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.
+  /* Should the error message in the status object according to this code. */
   void (*set_message)(upb_status* status, int code);
-));
+};
 
-// Object representing a success or failure status.
-// It owns no resources and allocates no memory, so it should work
-// even in OOM situations.
-UPB_DEFINE_CLASS0(upb::Status,
+#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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* Resets the status to a successful state with no message. */
   void Clear();
 
   void CopyFrom(const Status& other);
 
  private:
-  UPB_DISALLOW_COPY_AND_ASSIGN(Status);
-,
-UPB_DEFINE_STRUCT0(upb_status,
+  UPB_DISALLOW_COPY_AND_ASSIGN(Status)
+#else
+struct upb_status {
+#endif
   bool ok_;
 
-  // Specific status code defined by some error space (optional).
+  /* Specific status code defined by some error space (optional). */
   int code_;
   upb_errorspace *error_space_;
 
-  // Error message; NULL-terminated.
+  /* Error message; NULL-terminated. */
   char msg[UPB_STATUS_MAX_MESSAGE];
-));
+};
 
 #define UPB_STATUS_INIT {true, 0, NULL, {0}}
 
@@ -481,15 +519,15 @@
 extern "C" {
 #endif
 
-// The returned string is invalidated by any other call into the status.
+/* 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.
+/* 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, ...);
@@ -498,11 +536,11 @@
 void upb_status_copy(upb_status *to, const upb_status *from);
 
 #ifdef __cplusplus
-}  // extern "C"
+}  /* extern "C" */
 
 namespace upb {
 
-// C++ Wrappers
+/* C++ Wrappers */
 inline Status::Status() { Clear(); }
 inline bool Status::ok() const { return upb_ok(this); }
 inline const char* Status::error_message() const {
@@ -525,7 +563,7 @@
   upb_status_copy(this, &other);
 }
 
-}  // namespace upb
+}  /* namespace upb */
 
 #endif
 
@@ -538,9 +576,9 @@
 
 /* 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.
+/* 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,
@@ -550,85 +588,54 @@
   UPB_CTYPE_CSTR     = 6,
   UPB_CTYPE_PTR      = 7,
   UPB_CTYPE_CONSTPTR = 8,
-  UPB_CTYPE_FPTR     = 9,
+  UPB_CTYPE_FPTR     = 9
 } upb_ctype_t;
 
-typedef union {
-  int32_t  int32;
-  int64_t  int64;
-  uint64_t uint64;
-  uint32_t uint32;
-  bool     _bool;
-  char     *cstr;
-  void     *ptr;
-  const void *constptr;
-  upb_func *fptr;
-} _upb_value;
-
 typedef struct {
-  _upb_value val;
+  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.
+  /* 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 UPB_C99
-#define UPB_VALUE_INIT(v, member) {.member = v}
-#endif
-#define UPB__VALUE_INIT_NONE      UPB_VALUE_INIT(NULL, ptr)
-
 #ifdef NDEBUG
 #define SET_TYPE(dest, val)      UPB_UNUSED(val)
-#define UPB_VALUE_INIT_NONE      {UPB__VALUE_INIT_NONE}
 #else
 #define SET_TYPE(dest, val) dest = val
-// Non-existent type, all reads will fail.
-#define UPB_VALUE_INIT_NONE      {UPB__VALUE_INIT_NONE, -1}
 #endif
 
-#define UPB_VALUE_INIT_INT32(v)  UPB_VALUE_INIT(v, int32)
-#define UPB_VALUE_INIT_INT64(v)  UPB_VALUE_INIT(v, int64)
-#define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32)
-#define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64)
-#define UPB_VALUE_INIT_BOOL(v)   UPB_VALUE_INIT(v, _bool)
-#define UPB_VALUE_INIT_CSTR(v)   UPB_VALUE_INIT(v, cstr)
-#define UPB_VALUE_INIT_PTR(v)    UPB_VALUE_INIT(v, ptr)
-#define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr)
-#define UPB_VALUE_INIT_FPTR(v)   UPB_VALUE_INIT(v, fptr)
-
-// Like strdup(), which isn't always available since it's not ANSI C.
+/* 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.
+/* 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, _upb_value val,
+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(_upb_value val, upb_ctype_t 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, proto_type) \
+/* 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.uint64 = 0; \
+    val->val = (converter)cval; \
     SET_TYPE(val->ctype, proto_type); \
-    val->val.membername = cval; \
   } \
   UPB_INLINE upb_value upb_value_ ## name(type_t val) { \
     upb_value ret; \
@@ -637,69 +644,148 @@
   } \
   UPB_INLINE type_t upb_value_get ## name(upb_value val) { \
     assert(val.ctype == proto_type); \
-    return val.val.membername; \
+    return (type_t)(converter)val.val; \
   }
 
-FUNCS(int32,    int32,        int32_t,      UPB_CTYPE_INT32);
-FUNCS(int64,    int64,        int64_t,      UPB_CTYPE_INT64);
-FUNCS(uint32,   uint32,       uint32_t,     UPB_CTYPE_UINT32);
-FUNCS(uint64,   uint64,       uint64_t,     UPB_CTYPE_UINT64);
-FUNCS(bool,     _bool,        bool,         UPB_CTYPE_BOOL);
-FUNCS(cstr,     cstr,         char*,        UPB_CTYPE_CSTR);
-FUNCS(ptr,      ptr,          void*,        UPB_CTYPE_PTR);
-FUNCS(constptr, constptr,     const void*,  UPB_CTYPE_CONSTPTR);
-FUNCS(fptr,     fptr,         upb_func*,    UPB_CTYPE_FPTR);
+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 union {
-  uintptr_t num;
-  struct {
-    // We own this. NULL-terminated but may also contain binary data; see
-    // explicit length below.
-    // TODO: move the length to the start of the string in order to reduce
-    // tabkey's size (to one machine word) in a way that supports static
-    // initialization.
-    const char *str;
-    size_t length;
-  } s;
-} upb_tabkey;
-
-#define UPB_TABKEY_NUM(n) {n}
-#ifdef UPB_C99
-// Given that |s| is a string literal, sizeof(s) gives us a
-// compile-time-constant strlen(). We must ensure that this works for static
-// data initializers.
-#define UPB_TABKEY_STR(strval) { .s = { .str = strval,                    \
-                                        .length = sizeof(strval) - 1 } }
-#endif
-// TODO(haberman): C++
-#define UPB_TABKEY_NONE {0}
-
 typedef struct _upb_tabent {
   upb_tabkey key;
-  _upb_value 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.
+  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 hash table part is 2^size_lg2 entries.
+  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.
+  /* 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;
 
@@ -714,10 +800,10 @@
   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_value *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_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) \
@@ -726,8 +812,7 @@
 #define UPB_EMPTY_INTTABLE_INIT(ctype) \
   UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0)
 
-#define UPB_ARRAY_EMPTYVAL -1
-#define UPB_ARRAY_EMPTYENT UPB_VALUE_INIT_INT64(UPB_ARRAY_EMPTYVAL)
+#define UPB_ARRAY_EMPTYENT -1
 
 UPB_INLINE size_t upb_table_size(const upb_table *t) {
   if (t->size_lg2 == 0)
@@ -736,18 +821,16 @@
     return 1 << t->size_lg2;
 }
 
-// Internal-only functions, in .h file only out of necessity.
+/* Internal-only functions, in .h file only out of necessity. */
 UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
-  return e->key.num == 0;
+  return e->key == 0;
 }
 
-// Used by some of the unit tests for generic hashing functionality.
+/* 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 upb_tabkey upb_intkey(uintptr_t key) {
-  upb_tabkey k;
-  k.num = key;
-  return k;
+UPB_INLINE uintptr_t upb_intkey(uintptr_t key) {
+  return key;
 }
 
 UPB_INLINE uint32_t upb_inthash(uintptr_t key) {
@@ -758,93 +841,94 @@
   return t->entries + (hash & t->mask);
 }
 
-UPB_INLINE bool upb_arrhas(_upb_value v) {
-  return v.uint64 != (uint64_t)UPB_ARRAY_EMPTYVAL;
+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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+/* 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.
+  *v = upb_value_int32(0);  /* Silence compiler warnings. */
   if (key < t->array_size) {
-    _upb_value arrval = t->array[key];
+    upb_tabval arrval = t->array[key];
     if (upb_arrhas(arrval)) {
-      _upb_value_setval(v, arrval, t->t.ctype);
+      _upb_value_setval(v, arrval.val, t->t.ctype);
       return true;
     } else {
       return false;
@@ -853,8 +937,8 @@
     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.num == key) {
-        _upb_value_setval(v, e->val, t->t.ctype);
+      if ((uint32_t)e->key == key) {
+        _upb_value_setval(v, e->val.val, t->t.ctype);
         return true;
       }
       if (e->next == NULL) return false;
@@ -862,42 +946,43 @@
   }
 }
 
-// Exposed for testing only.
+/* 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).
+/* 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);
-//     // ...
-//   }
+/*   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;
@@ -917,13 +1002,14 @@
 
 /* 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);
-//     // ...
-//   }
+/*   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;
@@ -947,151 +1033,86 @@
 
 #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).
-#ifndef NDEBUG
-#define UPB_DEBUG_REFS
-#endif
+/* 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);
+UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted)
 
 struct upb_refcounted_vtbl;
 
-UPB_DEFINE_CLASS0(upb::RefCounted,
+#ifdef __cplusplus
+
+class upb::RefCounted {
  public:
-  // Returns true if the given object is frozen.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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);
-,
-UPB_DEFINE_STRUCT0(upb_refcounted,
-  // A single reference count shared by all objects in the group.
+  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.
+  /* A singly-linked list of all objects in the group. */
   upb_refcounted *next;
 
-  // Table of function pointers for this type.
+  /* 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.
+  /* 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.
+  upb_inttable *refs;  /* Maps owner -> trackedref for incoming refs. */
+  upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */
 #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);
-
-
-// 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 UPB_DEBUG_REFS
 #define UPB_REFCOUNT_INIT(refs, ref2s) \
     {&static_refcount, NULL, NULL, 0, true, refs, ref2s}
@@ -1099,8 +1120,117 @@
 #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.
+/* C++ Wrappers. */
 namespace upb {
 inline bool RefCounted::IsFrozen() const {
   return upb_refcounted_isfrozen(this);
@@ -1117,10 +1247,10 @@
 inline void RefCounted::CheckRef(const void *owner) const {
   upb_refcounted_checkref(this, owner);
 }
-}  // namespace upb
+}  /* namespace upb */
 #endif
 
-#endif  // UPB_REFCOUNT_H_
+#endif  /* UPB_REFCOUNT_H_ */
 
 #ifdef __cplusplus
 #include <cstring>
@@ -1136,114 +1266,90 @@
 }
 #endif
 
-UPB_DECLARE_TYPE(upb::Def, upb_def);
-UPB_DECLARE_TYPE(upb::EnumDef, upb_enumdef);
-UPB_DECLARE_TYPE(upb::FieldDef, upb_fielddef);
-UPB_DECLARE_TYPE(upb::MessageDef, upb_msgdef);
-UPB_DECLARE_TYPE(upb::OneofDef, upb_oneofdef);
+UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted)
 
-// Maximum field number allowed for FieldDefs.  This is an inherent limit of the
-// protobuf wire format.
-#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
-
-// 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.
+/* 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.
+/* 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_DEF_SERVICE,   /* Not yet implemented. */
+  UPB_DEF_ANY = -1   /* Wildcard for upb_symtab_get*() */
 } upb_deftype_t;
 
-// The base class of all defs.  Its base is upb::RefCounted (use upb::upcast()
-// to convert).
-UPB_DEFINE_CLASS1(upb::Def, upb::RefCounted,
+#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;
 
-  // Functionality from upb::RefCounted.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void* from, const void* to) const;
-  void CheckRef(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).
+  /* "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.
+  /* 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!
+  /* 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);
-,
-UPB_DEFINE_STRUCT(upb_def, upb_refcounted,
-  const char *fullname;
-  upb_deftype_t type : 8;
-  // 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;
-));
+  UPB_DISALLOW_POD_OPS(Def, upb::Def)
+};
 
-#define UPB_DEF_INIT(name, type, refs, ref2s) \
-    { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false }
+#endif  /* __cplusplus */
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// Native C API.
+/* Native C API. */
 upb_def *upb_def_dup(const upb_def *def, const void *owner);
 
-// From upb_refcounted.
-bool upb_def_isfrozen(const upb_def *def);
-void upb_def_ref(const upb_def *def, const void *owner);
-void upb_def_unref(const upb_def *def, const void *owner);
-void upb_def_donateref(const upb_def *def, const void *from, const void *to);
-void upb_def_checkref(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_END_EXTERN_C
 
 
 /* upb::Def casts *************************************************************/
@@ -1276,14 +1382,14 @@
   inline const cpptype *dyn_cast<const cpptype *, Def>(Def * def) {            \
     return upb_dyncast_##cname(def);                                           \
   }                                                                            \
-  }  // namespace upb
+  }  /* namespace upb */
 #else
 #define UPB_CPP_CASTS(cname, cpptype)
-#endif
+#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.
+/* 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;                 \
@@ -1302,16 +1408,30 @@
   UPB_CPP_CASTS(lower, cpptype)
 
 #define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members)             \
-  UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, UPB_QUOTE(cppmethods), \
+  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).
+/* 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,
@@ -1319,29 +1439,29 @@
   UPB_TYPE_STRING   = 4,
   UPB_TYPE_BYTES    = 5,
   UPB_TYPE_MESSAGE  = 6,
-  UPB_TYPE_ENUM     = 7,  // Enum values are int32.
+  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_TYPE_UINT64   = 11
 } upb_fieldtype_t;
 
-// The repeated-ness of each field; this matches descriptor.proto.
+/* 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_REPEATED = 3
 } upb_label_t;
 
-// How integers should be encoded in serializations that offer multiple
-// integer encoding methods.
+/* 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_ZIGZAG = 3   /* Only for signed types (INT32/INT64). */
 } upb_intfmt_t;
 
-// Descriptor types, as defined in descriptor.proto.
+/* Descriptor types, as defined in descriptor.proto. */
 typedef enum {
   UPB_DESCRIPTOR_TYPE_DOUBLE   = 1,
   UPB_DESCRIPTOR_TYPE_FLOAT    = 2,
@@ -1360,128 +1480,129 @@
   UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
   UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
   UPB_DESCRIPTOR_TYPE_SINT32   = 17,
-  UPB_DESCRIPTOR_TYPE_SINT64   = 18,
+  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)
 
-// 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).
-UPB_DEFINE_DEF(upb::FieldDef, fielddef, FIELD,
+#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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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;
 
-  // Functionality from upb::RefCounted.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void* from, const void* to) const;
-  void CheckRef(const void* owner) const;
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
 
-  // Functionality from upb::Def.
+  /* Functionality from upb::Def. */
   const char* full_name() const;
 
-  bool type_is_set() const;  // Whether 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 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).
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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;
@@ -1490,83 +1611,81 @@
   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.
+  /* 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
+  /* 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.
+  /* 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.
+  /* 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).
+  /* 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.
+  /* 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!
-  //////////////////////////////////////////////////////////////////////////////
+  /* 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).
+  /* 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.
+  /* 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.
+  /* 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).
+  /* "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.
+  /* "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);
@@ -1574,12 +1693,12 @@
   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.
+  /* 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);
@@ -1591,15 +1710,15 @@
   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.
+  /* 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);
@@ -1607,66 +1726,21 @@
   bool set_subdef_name(const std::string &name, Status* s);
 
  private:
-  UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef);
-,
-UPB_DEFINE_STRUCT(upb_fielddef, upb_def,
-  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_;
-));
+  UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef)
+};
 
-#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 \
-  }
+# endif  /* defined(__cplusplus) */
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// Native C API.
+/* Native C API. */
 upb_fielddef *upb_fielddef_new(const void *owner);
 upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner);
 
-// From upb_refcounted.
-bool upb_fielddef_isfrozen(const upb_fielddef *f);
-void upb_fielddef_ref(const upb_fielddef *f, const void *owner);
-void upb_fielddef_unref(const upb_fielddef *f, const void *owner);
-void upb_fielddef_donateref(const upb_fielddef *f, const void *from,
-                            const void *to);
-void upb_fielddef_checkref(const upb_fielddef *f, const void *owner);
+/* Include upb_refcounted methods like upb_fielddef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_fielddef, upb_fielddef_upcast2)
 
-// From upb_def.
+/* 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);
@@ -1745,7 +1819,7 @@
 bool upb_fielddef_checkdescriptortype(int32_t type);
 bool upb_fielddef_checkintfmt(int32_t fmt);
 
-UPB_END_EXTERN_C  // }
+UPB_END_EXTERN_C
 
 
 /* upb::MessageDef ************************************************************/
@@ -1753,66 +1827,64 @@
 typedef upb_inttable_iter upb_msg_field_iter;
 typedef upb_strtable_iter upb_msg_oneof_iter;
 
-// Structure that describes a single .proto message type.
-//
-// Its base class is upb::Def (use upb::upcast() to convert).
-UPB_DEFINE_DEF(upb::MessageDef, msgdef, MSG, UPB_QUOTE(
+#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.
+  /* Returns NULL if memory allocation failed. */
   static reffed_ptr<MessageDef> New();
 
-  // Functionality from upb::RefCounted.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void* from, const void* to) const;
-  void CheckRef(const void* owner) const;
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
 
-  // Functionality from upb::Def.
+  /* 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().
+  /* 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.
+  /* The number of fields that belong to the MessageDef. */
   int field_count() const;
 
-  // The number of oneofs that belong to the MessageDef.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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;
@@ -1854,21 +1926,21 @@
     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?
+  /* 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?
+  /* Is this message a map entry? */
   void setmapentry(bool map_entry);
   bool mapentry() const;
 
-  // Iteration over fields.  The order is undefined.
+  /* Iteration over fields.  The order is undefined. */
   class field_iterator
       : public std::iterator<std::forward_iterator_tag, FieldDef*> {
    public:
@@ -1899,7 +1971,7 @@
     upb_msg_field_iter iter_;
   };
 
-  // Iteration over oneofs. The order is undefined.
+  /* Iteration over oneofs. The order is undefined. */
   class oneof_iterator
       : public std::iterator<std::forward_iterator_tag, FieldDef*> {
    public:
@@ -1982,52 +2054,21 @@
   ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); }
 
  private:
-  UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef);
-),
-UPB_DEFINE_STRUCT(upb_msgdef, upb_def,
-  size_t selector_count;
-  uint32_t submsg_field_count;
+  UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef)
+};
 
-  // Tables for looking up fields by number and name.
-  upb_inttable itof;  // int to field
-  upb_strtable ntof;  // name to field
+#endif  /* __cplusplus */
 
-  // Tables for looking up oneofs by name.
-  upb_strtable ntoo;  // name to oneof
+UPB_BEGIN_EXTERN_C
 
-  // 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_BEGIN_EXTERN_C  // {
-
-// Returns NULL if memory allocation failed.
+/* Returns NULL if memory allocation failed. */
 upb_msgdef *upb_msgdef_new(const void *owner);
 
-// From upb_refcounted.
-bool upb_msgdef_isfrozen(const upb_msgdef *m);
-void upb_msgdef_ref(const upb_msgdef *m, const void *owner);
-void upb_msgdef_unref(const upb_msgdef *m, const void *owner);
-void upb_msgdef_donateref(const upb_msgdef *m, const void *from,
-                          const void *to);
-void upb_msgdef_checkref(const upb_msgdef *m, 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);
 
-// From upb_def.
 const char *upb_msgdef_fullname(const upb_msgdef *m);
 bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s);
 
@@ -2037,10 +2078,10 @@
 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.
+/* 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);
@@ -2060,9 +2101,9 @@
   return (upb_fielddef *)upb_msgdef_ntof(m, name, len);
 }
 
-// Oneof lookup:
-//   - ntoo = name to oneof
-//   - ntooz = name to oneof, null-terminated string.
+/* 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);
@@ -2080,7 +2121,7 @@
 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.
+/* Well-known field tag numbers for map-entry messages. */
 #define UPB_MAPENTRY_KEY   1
 #define UPB_MAPENTRY_VALUE 2
 
@@ -2088,95 +2129,94 @@
                                           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.
+/* 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.
+/* 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_END_EXTERN_C
 
 
 /* upb::EnumDef ***************************************************************/
 
 typedef upb_strtable_iter upb_enum_iter;
 
-// Class that represents an enum.  Its base class is upb::Def (convert with
-// upb::upcast()).
-UPB_DEFINE_DEF(upb::EnumDef, enumdef, ENUM,
+#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.
+  /* Returns NULL if memory allocation failed. */
   static reffed_ptr<EnumDef> New();
 
-  // Functionality from upb::RefCounted.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void* from, const void* to) const;
-  void CheckRef(const void* owner) const;
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
 
-  // Functionality from upb::Def.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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?
+  /* 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*);
@@ -2191,33 +2231,23 @@
   };
 
  private:
-  UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef);
-,
-UPB_DEFINE_STRUCT(upb_enumdef, upb_def,
-  upb_strtable ntoi;
-  upb_inttable iton;
-  int32_t defaultval;
-));
+  UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef)
+};
 
-#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \
-  { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntoi, iton, defaultval }
+#endif  /* __cplusplus */
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// Native C API.
+/* Native C API. */
 upb_enumdef *upb_enumdef_new(const void *owner);
 upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner);
 
-// From upb_refcounted.
-void upb_enumdef_unref(const upb_enumdef *e, const void *owner);
-bool upb_enumdef_isfrozen(const upb_enumdef *e);
-void upb_enumdef_ref(const upb_enumdef *e, const void *owner);
-void upb_enumdef_donateref(const upb_enumdef *m, const void *from,
-                           const void *to);
-void upb_enumdef_checkref(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.
+/* 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);
@@ -2228,10 +2258,11 @@
 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.
+/* 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,
@@ -2240,66 +2271,65 @@
 }
 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)) {
-//    // ...
-//  }
+/*  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_END_EXTERN_C
 
 /* upb::OneofDef **************************************************************/
 
 typedef upb_inttable_iter upb_oneof_iter;
 
-// Class that represents a oneof.  Its base class is upb::Def (convert with
-// upb::upcast()).
-UPB_DEFINE_DEF(upb::OneofDef, oneofdef, ONEOF, UPB_QUOTE(
+#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.
+  /* Returns NULL if memory allocation failed. */
   static reffed_ptr<OneofDef> New();
 
-  // Functionality from upb::RefCounted.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void* from, const void* to) const;
-  void CheckRef(const void* owner) const;
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
 
-  // Functionality from upb::Def.
+  /* Functionality from upb::Def. */
   const char* full_name() const;
 
-  // Returns the MessageDef that owns this OneofDef.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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 {
@@ -2318,14 +2348,14 @@
     return FindFieldByName(str.c_str(), str.size());
   }
 
-  // Looks up by tag number.
+  /* 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.
+  /* 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.
+  /* Iteration over fields.  The order is undefined. */
   class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
    public:
     explicit iterator(OneofDef* md);
@@ -2361,30 +2391,19 @@
   const_iterator end() const;
 
  private:
-  UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef);
-),
-UPB_DEFINE_STRUCT(upb_oneofdef, upb_def,
-  upb_strtable ntof;
-  upb_inttable itof;
-  const upb_msgdef *parent;
-));
+  UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef)
+};
 
-#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
-  { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntof, itof }
+#endif  /* __cplusplus */
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// Native C API.
+/* Native C API. */
 upb_oneofdef *upb_oneofdef_new(const void *owner);
 upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner);
 
-// From upb_refcounted.
-void upb_oneofdef_unref(const upb_oneofdef *o, const void *owner);
-bool upb_oneofdef_isfrozen(const upb_oneofdef *e);
-void upb_oneofdef_ref(const upb_oneofdef *o, const void *owner);
-void upb_oneofdef_donateref(const upb_oneofdef *m, const void *from,
-                           const void *to);
-void upb_oneofdef_checkref(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);
@@ -2395,10 +2414,10 @@
                            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.
+/* 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,
@@ -2407,17 +2426,18 @@
 }
 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)) {
-//    // ...
-//  }
+/*  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_END_EXTERN_C
 
 #ifdef __cplusplus
 
@@ -2426,21 +2446,12 @@
   return str.c_str();
 }
 
-// Inline C++ wrappers.
+/* Inline C++ wrappers. */
 namespace upb {
 
 inline Def* Def::Dup(const void* owner) const {
   return upb_def_dup(this, owner);
 }
-inline bool Def::IsFrozen() const { return upb_def_isfrozen(this); }
-inline void Def::Ref(const void* owner) const { upb_def_ref(this, owner); }
-inline void Def::Unref(const void* owner) const { upb_def_unref(this, owner); }
-inline void Def::DonateRef(const void* from, const void* to) const {
-  upb_def_donateref(this, from, to);
-}
-inline void Def::CheckRef(const void* owner) const {
-  upb_def_checkref(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) {
@@ -2492,19 +2503,6 @@
 inline FieldDef* FieldDef::Dup(const void* owner) const {
   return upb_fielddef_dup(this, owner);
 }
-inline bool FieldDef::IsFrozen() const { return upb_fielddef_isfrozen(this); }
-inline void FieldDef::Ref(const void* owner) const {
-  upb_fielddef_ref(this, owner);
-}
-inline void FieldDef::Unref(const void* owner) const {
-  upb_fielddef_unref(this, owner);
-}
-inline void FieldDef::DonateRef(const void* from, const void* to) const {
-  upb_fielddef_donateref(this, from, to);
-}
-inline void FieldDef::CheckRef(const void* owner) const {
-  upb_fielddef_checkref(this, owner);
-}
 inline const char* FieldDef::full_name() const {
   return upb_fielddef_fullname(this);
 }
@@ -2670,19 +2668,6 @@
   upb_msgdef *m = upb_msgdef_new(&m);
   return reffed_ptr<MessageDef>(m, &m);
 }
-inline bool MessageDef::IsFrozen() const { return upb_msgdef_isfrozen(this); }
-inline void MessageDef::Ref(const void* owner) const {
-  return upb_msgdef_ref(this, owner);
-}
-inline void MessageDef::Unref(const void* owner) const {
-  return upb_msgdef_unref(this, owner);
-}
-inline void MessageDef::DonateRef(const void* from, const void* to) const {
-  return upb_msgdef_donateref(this, from, to);
-}
-inline void MessageDef::CheckRef(const void* owner) const {
-  return upb_msgdef_checkref(this, owner);
-}
 inline const char *MessageDef::full_name() const {
   return upb_msgdef_fullname(this);
 }
@@ -2870,19 +2855,6 @@
   upb_enumdef *e = upb_enumdef_new(&e);
   return reffed_ptr<EnumDef>(e, &e);
 }
-inline bool EnumDef::IsFrozen() const { return upb_enumdef_isfrozen(this); }
-inline void EnumDef::Ref(const void* owner) const {
-  return upb_enumdef_ref(this, owner);
-}
-inline void EnumDef::Unref(const void* owner) const {
-  return upb_enumdef_unref(this, owner);
-}
-inline void EnumDef::DonateRef(const void* from, const void* to) const {
-  return upb_enumdef_donateref(this, from, to);
-}
-inline void EnumDef::CheckRef(const void* owner) const {
-  return upb_enumdef_checkref(this, owner);
-}
 inline const char* EnumDef::full_name() const {
   return upb_enumdef_fullname(this);
 }
@@ -2935,19 +2907,6 @@
   upb_oneofdef *o = upb_oneofdef_new(&o);
   return reffed_ptr<OneofDef>(o, &o);
 }
-inline bool OneofDef::IsFrozen() const { return upb_oneofdef_isfrozen(this); }
-inline void OneofDef::Ref(const void* owner) const {
-  return upb_oneofdef_ref(this, owner);
-}
-inline void OneofDef::Unref(const void* owner) const {
-  return upb_oneofdef_unref(this, owner);
-}
-inline void OneofDef::DonateRef(const void* from, const void* to) const {
-  return upb_oneofdef_donateref(this, from, to);
-}
-inline void OneofDef::CheckRef(const void* owner) const {
-  return upb_oneofdef_checkref(this, owner);
-}
 inline const char* OneofDef::full_name() const {
   return upb_oneofdef_name(this);
 }
@@ -3029,1047 +2988,197 @@
   return !(*this == other);
 }
 
-}  // namespace upb
+}  /* namespace upb */
 #endif
 
-#undef UPB_DEFINE_DEF
-#undef UPB_DEF_CASTS
-#undef UPB_CPP_CASTS
-
 #endif /* UPB_DEF_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_
-
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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_SYMTAB_H_
-#define UPB_SYMTAB_H_
 
+#ifndef UPB_STATICINIT_H_
+#define UPB_STATICINIT_H_
 
 #ifdef __cplusplus
-#include <vector>
-namespace upb { class SymbolTable; }
+/* 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_DECLARE_TYPE(upb::SymbolTable, upb_symtab);
+/* upb_refcounted *************************************************************/
 
-typedef struct {
- UPB_PRIVATE_FOR_CPP
-  upb_strtable_iter iter;
-  upb_deftype_t type;
-} upb_symtab_iter;
 
-// Non-const methods in upb::SymbolTable are NOT thread-safe.
-UPB_DEFINE_CLASS1(upb::SymbolTable, upb::RefCounted,
- public:
-  // Returns a new symbol table with a single ref owned by "owner."
-  // Returns NULL if memory allocation failed.
-  static reffed_ptr<SymbolTable> New();
+/* upb_def ********************************************************************/
 
-  // Functionality from upb::RefCounted.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void *from, const void *to) const;
-  void CheckRef(const void *owner) const;
+struct upb_def {
+  upb_refcounted base;
 
-  // 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.
+  const char *fullname;
+  char type;  /* A upb_deftype_t (char to save space) */
 
-  // 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();
+  /* 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;
+};
 
-  // 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;
+#define UPB_DEF_INIT(name, type, refs, ref2s) \
+    { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false }
 
-  // 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*.
+/* upb_fielddef ***************************************************************/
 
-  // 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);
+struct upb_fielddef {
+  upb_def base;
 
-  bool Add(const std::vector<Def*>& defs, void *owner, Status* status) {
-    return Add((Def*const*)&defs[0], defs.size(), owner, status);
+  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 \
   }
 
- private:
-  UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable);
-,
-UPB_DEFINE_STRUCT(upb_symtab, upb_refcounted,
+
+/* 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 }
 
-UPB_BEGIN_EXTERN_C  // {
 
-// Native C API.
-// From upb_refcounted.
-bool upb_symtab_isfrozen(const upb_symtab *s);
-void upb_symtab_ref(const upb_symtab *s, const void *owner);
-void upb_symtab_unref(const upb_symtab *s, const void *owner);
-void upb_symtab_donateref(
-    const upb_symtab *s, const void *from, const void *to);
-void upb_symtab_checkref(const upb_symtab *s, const void *owner);
-
-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 bool SymbolTable::IsFrozen() const {
-  return upb_symtab_isfrozen(this);
-}
-inline void SymbolTable::Ref(const void *owner) const {
-  upb_symtab_ref(this, owner);
-}
-inline void SymbolTable::Unref(const void *owner) const {
-  upb_symtab_unref(this, owner);
-}
-inline void SymbolTable::DonateRef(const void *from, const void *to) const {
-  upb_symtab_donateref(this, from, to);
-}
-inline void SymbolTable::CheckRef(const void *owner) const {
-  upb_symtab_checkref(this, owner);
-}
-
-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_ */
-
-#ifdef __cplusplus
-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); }
-
-#ifdef __cplusplus
-};  // extern "C"
-#endif
-
-#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_
+#endif  /* UPB_STATICINIT_H_ */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2010-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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
@@ -4083,25 +3192,26 @@
 class Handlers;
 template <class T> class Handler;
 template <class T> struct CanonicalType;
-}  // namespace upb
+}  /* 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_TYPE(upb::Handlers, upb_handlers);
+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.
+/* 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.
+/* 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,
@@ -4116,25 +3226,25 @@
   UPB_HANDLER_STARTSUBMSG,
   UPB_HANDLER_ENDSUBMSG,
   UPB_HANDLER_STARTSEQ,
-  UPB_HANDLER_ENDSEQ,
+  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.
+/* 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").
+/* 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++.
+/* 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);
@@ -4153,104 +3263,111 @@
 UPB_END_EXTERN_C
 
 
-// Static selectors for upb::Handlers.
+/* 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.
+/* 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);
 
-// A set of attributes that accompanies a handler's function pointer.
-UPB_DEFINE_CLASS0(upb::HandlerAttributes,
+#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().
+  /* 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.
+  /* 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).
+  /* 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.
+  /* 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);
-,
-UPB_DEFINE_STRUCT0(upb_handlerattr,
+#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.
+
+  /* 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;
 
-// 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.
-UPB_DEFINE_CLASS0(upb::BufferHandle,
+#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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* Returns NULL if the attached object is not of this type. */
   template <class T>
   const T* GetAttachedObject() const;
 
@@ -4265,26 +3382,29 @@
   friend UPB_INLINE const void* ::upb_bufhandle_objtype(
       const upb_bufhandle *h);
   friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h);
-,
-UPB_DEFINE_STRUCT0(upb_bufhandle,
+#else
+struct upb_bufhandle {
+#endif
   const char *buf_;
   const void *obj_;
   const void *objtype_;
   size_t objofs_;
-));
+};
 
-// 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.
-UPB_DEFINE_CLASS1(upb::Handlers, upb::RefCounted,
+#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;
@@ -4309,95 +3429,94 @@
   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.
+  /* 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.
+  /* 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.
+  /* 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.
-  bool IsFrozen() const;
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void *from, const void *to) const;
-  void CheckRef(const void *owner) const;
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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;
-  //   }
+  /* 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.
-  //   }
+  /* 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.
+  /* 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);
@@ -4406,240 +3525,247 @@
   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));
+  /* 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;
-  //   }
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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);
+  /* 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);
+  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;
 
-,
-UPB_DEFINE_STRUCT(upb_handlers, upb_refcounted,
   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.
-));
-
+  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));
+/* 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.
+/* 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.
+/* 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"
+/* 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
+#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.
+/* 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.
+/* 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.
+/* 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.
+  /* The underlying, handler function signature that upb uses internally. */
   typedef T FuncPtr;
 
-  // Intentionally implicit.
+  /* Intentionally implicit. */
   template <class F> Handler(F func);
   ~Handler();
 
@@ -4651,7 +3777,7 @@
     }
   }
 
-  UPB_DISALLOW_COPY_AND_ASSIGN(Handler);
+  UPB_DISALLOW_COPY_AND_ASSIGN(Handler)
   friend class Handlers;
   FuncPtr handler_;
   mutable HandlerAttributes attr_;
@@ -4660,15 +3786,15 @@
   upb_handlerfree *cleanup_func_;
 };
 
-}  // namespace upb
+}  /* namespace upb */
 
-#endif  // __cplusplus
+#endif  /* __cplusplus */
 
 UPB_BEGIN_EXTERN_C
 
-// Native C API.
+/* Native C API. */
 
-// Handler function typedefs.
+/* 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);
@@ -4685,10 +3811,10 @@
 typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
                                       size_t n, const upb_bufhandle* handle);
 
-// upb_bufhandle
+/* upb_bufhandle */
 size_t upb_bufhandle_objofs(const upb_bufhandle *h);
 
-// upb_handlerattr
+/* upb_handlerattr */
 void upb_handlerattr_init(upb_handlerattr *attr);
 void upb_handlerattr_uninit(upb_handlerattr *attr);
 
@@ -4706,7 +3832,7 @@
   return attr->handler_data_;
 }
 
-// upb_handlers
+/* 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);
@@ -4714,12 +3840,9 @@
                                            const void *owner,
                                            upb_handlers_callback *callback,
                                            const void *closure);
-bool upb_handlers_isfrozen(const upb_handlers *h);
-void upb_handlers_ref(const upb_handlers *h, const void *owner);
-void upb_handlers_unref(const upb_handlers *h, const void *owner);
-void upb_handlers_donateref(const upb_handlers *h, const void *from,
-                            const void *to);
-void upb_handlers_checkref(const upb_handlers *h, const void *owner);
+
+/* 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);
@@ -4790,28 +3913,29 @@
   return upb_handlerattr_handlerdata(&h->table[s].attr);
 }
 
-// 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.
-UPB_DEFINE_CLASS0(upb::BytesHandler,
+#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();
-,
-UPB_DEFINE_STRUCT0(upb_byteshandler,
+#else
+struct upb_byteshandler {
+#endif
   upb_handlers_tabent table[3];
-));
+};
 
 void upb_byteshandler_init(upb_byteshandler *h);
-void upb_byteshandler_uninit(upb_byteshandler *h);
 
-// Caller must ensure that "d" outlives the handlers.
-// TODO(haberman): support handlerfree function for the data.
-// 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.
+/* 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,
@@ -4819,7 +3943,7 @@
 bool upb_byteshandler_setendstr(upb_byteshandler *h,
                                 upb_endfield_handlerfunc *func, void *d);
 
-// "Static" methods
+/* "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,
@@ -4828,108 +3952,25 @@
   return start + 1;
 }
 
-// Internal-only.
+/* Internal-only. */
 uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f);
 uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
 
 UPB_END_EXTERN_C
 
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * Inline definitions for handlers.h, which are particularly long and a bit
- * tricky.
- */
+** 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>
 
-// 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.
+/* C inline methods. */
 
-// 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
-
-// C inline methods.
-
-// upb_bufhandle
+/* upb_bufhandle */
 UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) {
   h->obj_ = NULL;
   h->objtype_ = NULL;
@@ -4962,33 +4003,117 @@
 
 #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.
+/* 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 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 FirstUnlessVoid {
+struct FirstUnlessVoidOrBool {
   typedef T1 value;
 };
 
 template <class T2>
-struct FirstUnlessVoid<void, T2> {
+struct FirstUnlessVoidOrBool<void, T2> {
+  typedef T2 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<bool, T2> {
   typedef T2 value;
 };
 
@@ -5008,27 +4133,27 @@
 template<class T>
 bool is_same<T, T>::value = true;
 
-// FuncInfo ////////////////////////////////////////////////////////////////////
+/* FuncInfo *******************************************************************/
 
-// Info about the user's original, pre-wrapped function.
+/* 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).
+  /* The type of the closure that the function takes (its first param). */
   typedef C Closure;
 
-  // The return type.
+  /* The return type. */
   typedef R Return;
 };
 
-// Func ////////////////////////////////////////////////////////////////////////
+/* 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.
+/* 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; }
@@ -5073,13 +4198,13 @@
   }
 };
 
-// BoundFunc ///////////////////////////////////////////////////////////////////
+/* 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.
+/* 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;
@@ -5119,13 +4244,13 @@
   explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
 };
 
-// FuncSig /////////////////////////////////////////////////////////////////////
+/* 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.
+/* 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)>
@@ -5190,41 +4315,41 @@
   }
 };
 
-// Overloaded template function that can construct the appropriate FuncSig*
-// class given a function pointer by deducing the template parameters.
+/* 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.
+  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.
+  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.
+  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.
+  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.
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
   return FuncSig5<R, P1, P2, P3, P4, P5>();
 }
 
-// MethodSig ///////////////////////////////////////////////////////////////////
+/* MethodSig ******************************************************************/
 
-// CallMethod*: a function template that calls a given method.
+/* CallMethod*: a function template that calls a given method. */
 template <class R, class C, R (C::*F)()>
 R CallMethod0(C *obj) {
   return ((*obj).*F)();
@@ -5251,10 +4376,10 @@
   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.
+/* 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)()>
@@ -5335,57 +4460,61 @@
 
 template <class R, class C>
 inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
-  UPB_UNUSED(f);  // Only used for template parameter deduction.
+  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.
+  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.
+  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.
+  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.
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
   return MethodSig4<R, C, P1, P2, P3, P4>();
 }
 
-// MaybeWrapReturn /////////////////////////////////////////////////////////////
+/* 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 is expected to return void* but doesn't, wrap it so it
-//      does (either by returning the closure param if the wrapped function
-//      returns void or by casting a different pointer type to void* for
-//      return).
+/* 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 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.
+/* 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.
+/* 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);
@@ -5398,7 +4527,7 @@
   return true;
 }
 
-// Function wrapper that munges the return value from void to (void*)arg1
+/* 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);
@@ -5411,7 +4540,7 @@
   return p1;
 }
 
-// Function wrapper that munges the return value from R to void*.
+/* 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);
@@ -5422,7 +4551,7 @@
   return F(p1, p2, p3);
 }
 
-// Function wrapper that munges the return value from bool to void*.
+/* 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;
@@ -5433,7 +4562,7 @@
   return F(p1, p2, p3) ? p1 : UPB_BREAK;
 }
 
-// For the string callback, which takes five params, returns the size param.
+/* 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,
@@ -5442,8 +4571,8 @@
   return p4;
 }
 
-// For the string callback, which takes five params, returns the size param or
-// zero.
+/* 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,
@@ -5451,8 +4580,8 @@
   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.
+/* 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;
@@ -5463,8 +4592,8 @@
   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.
+/* 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;
@@ -5475,8 +4604,8 @@
   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*.
+/* 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> {
@@ -5490,8 +4619,8 @@
       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.
+/* 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;
@@ -5503,8 +4632,8 @@
       Func;
 };
 
-// If our function returns void but we want one returning size_t, wrap it in a
-// function that returns the size argument.
+/* 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<
@@ -5514,8 +4643,8 @@
                 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.
+/* 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<
@@ -5525,16 +4654,16 @@
                 ReturnNOr0<P1, P2, F>, I> Func;
 };
 
-// ConvertParams ///////////////////////////////////////////////////////////////
+/* 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 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.
+/* 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);
@@ -5568,7 +4697,7 @@
   return F(static_cast<P1>(p1), p2, p3);
 }
 
-// Function that casts the handler data parameter.
+/* 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));
@@ -5593,7 +4722,7 @@
   return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
 }
 
-// For unbound functions, ignore the handler data.
+/* 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;
@@ -5607,8 +4736,8 @@
                 IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func;
 };
 
-// For StringBuffer only; this ignores both the handler data and the
-// BufferHandle.
+/* 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,
@@ -5623,7 +4752,7 @@
                 IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func;
 };
 
-// For bound functions, cast the handler data.
+/* 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>
@@ -5638,7 +4767,7 @@
                 CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func;
 };
 
-// For StringBuffer only; this ignores the BufferHandle.
+/* 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> {
@@ -5654,8 +4783,8 @@
                 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.
+/* 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;                                                        \
@@ -5670,22 +4799,22 @@
     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);
+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);
+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);
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64ALT_T)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T)
 #endif
 #undef TYPE_METHODS
 
@@ -5693,7 +4822,8 @@
   typedef Status* Type;
 };
 
-// Type methods that are only one-per-canonical-type and not one-per-cvariant.
+/* 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, \
@@ -5701,13 +4831,13 @@
       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);
+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;
@@ -5750,22 +4880,25 @@
       ReturnWrappedFunc;
   handler_ = ReturnWrappedFunc().Call;
 
-  // Set attributes based on what templates can statically tell us about the
-  // user's function.
+  /* 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.
+  /* 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.
+  /* 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.  This is all nonsense for non START* handlers, but it doesn't matter
-  // because in that case the value will be ignored.
-  typedef typename FirstUnlessVoid<typename F::FuncInfo::Return,
-                                   typename F::FuncInfo::Closure>::value
+  /* 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>());
 }
@@ -5834,19 +4967,6 @@
   const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
   return reffed_ptr<const Handlers>(h, &h);
 }
-inline bool Handlers::IsFrozen() const { return upb_handlers_isfrozen(this); }
-inline void Handlers::Ref(const void *owner) const {
-  upb_handlers_ref(this, owner);
-}
-inline void Handlers::Unref(const void *owner) const {
-  upb_handlers_unref(this, owner);
-}
-inline void Handlers::DonateRef(const void *from, const void *to) const {
-  upb_handlers_donateref(this, from, to);
-}
-inline void Handlers::CheckRef(const void *owner) const {
-  upb_handlers_checkref(this, owner);
-}
 inline const Status* Handlers::status() {
   return upb_handlers_status(this);
 }
@@ -5960,13 +5080,11 @@
   upb_byteshandler_init(this);
 }
 
-inline BytesHandler::~BytesHandler() {
-  upb_byteshandler_uninit(this);
-}
+inline BytesHandler::~BytesHandler() {}
 
-}  // namespace upb
+}  /* namespace upb */
 
-#endif  // __cplusplus
+#endif  /* __cplusplus */
 
 
 #undef UPB_TWO_32BIT_TYPES
@@ -5980,27 +5098,286 @@
 #undef UPB_INT64ALT_T
 #undef UPB_UINT64ALT_T
 
-#endif  // UPB_HANDLERS_INL_H_
+#endif  /* UPB_HANDLERS_INL_H_ */
 
-#endif  // UPB_HANDLERS_H
+#endif  /* UPB_HANDLERS_H */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2010-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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).
- */
+** 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
@@ -6014,109 +5391,90 @@
 }
 #endif
 
-UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc);
-UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink);
-UPB_DECLARE_TYPE(upb::Sink, upb_sink);
+UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc)
+UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink)
+UPB_DECLARE_TYPE(upb::Sink, upb_sink)
 
-// Internal-only struct for the sink.
-struct upb_sinkframe {
- UPB_PRIVATE_FOR_CPP
-  const upb_handlers *h;
-  void *closure;
+#ifdef __cplusplus
 
-  // For any frames besides the top, this is the END* callback that will run
-  // when the subframe is popped (for example, for a "sequence" frame the frame
-  // above it will be a UPB_HANDLER_ENDSEQ handler).  But this is only
-  // necessary for assertion checking inside upb_sink and can be omitted if the
-  // sink has only one caller.
-  //
-  // TODO(haberman): have a mechanism for ensuring that a sink only has one
-  // caller.
-  upb_selector_t selector;
-};
-
-// The maximum nesting depth that upb::Sink will allow.  Matches proto2's limit.
-// TODO: make this a runtime-settable property of Sink.
-#define UPB_SINK_MAX_NESTING 64
-
-// 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?
-UPB_DEFINE_CLASS0(upb::Sink,
+/* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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).
+  /* 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);
+  /* 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().
+  /* 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);
@@ -6125,92 +5483,101 @@
   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.
+  /* 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.
+  /* 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.
+  /* 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.
-,
-UPB_DEFINE_STRUCT0(upb_sink,
+  /* 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;
-));
+};
 
-UPB_DEFINE_CLASS0(upb::BytesSink,
+#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.
+  /* 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.
+  /* 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();
-,
-UPB_DEFINE_STRUCT0(upb_bytessink,
+#else
+struct upb_bytessink {
+#endif
   const upb_byteshandler *handler;
   void *closure;
-));
+};
 
-// 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.
-UPB_DEFINE_CLASS0(upb::BufferSource,
+#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.
+  /* 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.
+  /* 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);
   }
-,
-UPB_DEFINE_STRUCT0(upb_bufsrc,
-));
+#else
+struct upb_bufsrc {
+  char dummy;
+#endif
+};
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// Inline definitions.
+/* Inline definitions. */
 
 UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
                                     void *closure) {
@@ -6220,10 +5587,11 @@
 
 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;
-  upb_startstr_handlerfunc *start =
-      (upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
+  start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
 
   if (!start) return true;
   *subc = start(s->closure, upb_handlerattr_handlerdata(
@@ -6235,9 +5603,10 @@
 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;
-  upb_string_handlerfunc *putbuf =
-      (upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func;
+  putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func;
 
   if (!putbuf) return true;
   return putbuf(subc, upb_handlerattr_handlerdata(
@@ -6246,9 +5615,10 @@
 }
 
 UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
+  typedef upb_endfield_handlerfunc func;
+  func *end;
   if (!s->handler) return true;
-  upb_endfield_handlerfunc *end =
-      (upb_endfield_handlerfunc *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
+  end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
 
   if (!end) return true;
   return end(s->closure,
@@ -6259,12 +5629,13 @@
 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);
-  bool ret = upb_bytessink_start(sink, len, &subc);
+  ret = upb_bytessink_start(sink, len, &subc);
   if (ret && len != 0) {
-    ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) == len);
+    ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len);
   }
   if (ret) {
     ret = upb_bytessink_end(sink);
@@ -6276,21 +5647,23 @@
 #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;                                             \
-    upb_##type##_handlerfunc *func =                                           \
-        (upb_##type##_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); \
+    func = (functype *)upb_handlers_gethandler(s->handlers, sel);              \
     if (!func) return true;                                                    \
-    const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);            \
+    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);
+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) {
@@ -6301,114 +5674,129 @@
 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;
-  upb_string_handlerfunc *handler =
-      (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel);
+  handler = (func *)upb_handlers_gethandler(s->handlers, sel);
 
   if (!handler) return n;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  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;
-  upb_startmsg_handlerfunc *startmsg =
-      (upb_startmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
-                                                      UPB_STARTMSG_SELECTOR);
+  startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR);
+
   if (!startmsg) return true;
-  const void *hd =
-      upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
+  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;
-  upb_endmsg_handlerfunc *endmsg =
-      (upb_endmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
-                                                        UPB_ENDMSG_SELECTOR);
+  endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR);
 
   if (!endmsg) return true;
-  const void *hd =
-      upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
+  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;
-  upb_startfield_handlerfunc *startseq =
-      (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+  startseq = (func*)upb_handlers_gethandler(s->handlers, sel);
 
   if (!startseq) return true;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  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;
-  upb_endfield_handlerfunc *endseq =
-      (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+  endseq = (func*)upb_handlers_gethandler(s->handlers, sel);
 
   if (!endseq) return true;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  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;
-  upb_startstr_handlerfunc *startstr =
-      (upb_startstr_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+  startstr = (func*)upb_handlers_gethandler(s->handlers, sel);
 
   if (!startstr) return true;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  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;
-  upb_endfield_handlerfunc *endstr =
-      (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+  endstr = (func*)upb_handlers_gethandler(s->handlers, sel);
 
   if (!endstr) return true;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  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);
-  upb_startfield_handlerfunc *startsubmsg =
-      (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+  startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
 
   if (!startsubmsg) return true;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  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;
-  upb_endfield_handlerfunc *endsubmsg =
-      (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+  endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
 
   if (!endsubmsg) return s->closure;
-  const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
   return endsubmsg(s->closure, hd);
 }
 
-UPB_END_EXTERN_C  // }
+UPB_END_EXTERN_C
 
 #ifdef __cplusplus
 
@@ -6497,26 +5885,21 @@
   return upb_bufsrc_putbuf(buf, len, sink);
 }
 
-}  // namespace upb
+}  /* namespace upb */
 #endif
 
 #endif
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2013 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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
@@ -6534,33 +5917,33 @@
 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.
+  /* 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.
+  /* 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
+}  /* namespace upb */
 
 #endif
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// C API.
+/* 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  // }
+UPB_END_EXTERN_C
 
 #ifdef __cplusplus
-// C++ Wrappers.
+/* C++ Wrappers. */
 namespace upb {
 inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs,
                       int32_t hasbit) {
@@ -6570,19 +5953,200 @@
                                        FieldDef::Type* type) {
   return upb_shim_getdata(h, s, type);
 }
-}  // namespace upb
+}  /* namespace upb */
 #endif
 
-#endif  // UPB_SHIM_H
+#endif  /* UPB_SHIM_H */
 /*
- * upb - a minimalist implementation of protocol buffers.
+** 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);
+ *    // ...
+ * }
  *
- * Copyright (c) 2011 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * upb::descriptor::Reader provides a way of building upb::Defs from
- * data in descriptor.proto format.
- */
+ * 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
@@ -6592,157 +6156,894 @@
 namespace upb {
 namespace descriptor {
 class Reader;
-}  // namespace descriptor
-}  // namespace upb
+}  /* namespace descriptor */
+}  /* namespace upb */
 #endif
 
-UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader);
+UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader)
 
-// Internal-only structs used by Reader.
+#ifdef __cplusplus
 
-// upb_deflist is an internal-only dynamic array for storing a growing list of
-// upb_defs.
-typedef struct {
- UPB_PRIVATE_FOR_CPP
-  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 {
- UPB_PRIVATE_FOR_CPP
-  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
-
-// Class that receives descriptor data according to the descriptor.proto schema
-// and use it to build upb::Defs corresponding to that schema.
-UPB_DEFINE_CLASS0(upb::descriptor::Reader,
+/* 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.
-  Reader(const Handlers* handlers, Status* status);
-  ~Reader();
+  /* 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);
 
-  // Resets the reader's state and discards any defs it may have built.
-  void Reset();
-
-  // The reader's input; this is where descriptor.proto data should be sent.
+  /* 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.
+  /* 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."
+  /* Builds and returns handlers for the reader, owned by "owner." */
   static Handlers* NewHandlers(const void* owner);
-,
-UPB_DEFINE_STRUCT0(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;
+ private:
+  UPB_DISALLOW_POD_OPS(Reader, upb::descriptor::Reader)
+};
 
-  char *default_string;
+#endif
 
-  upb_fielddef *f;
-));
+UPB_BEGIN_EXTERN_C
 
-UPB_BEGIN_EXTERN_C  // {
-
-// C API.
-void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
-                         upb_status *status);
-void upb_descreader_uninit(upb_descreader *r);
-void upb_descreader_reset(upb_descreader *r);
+/* 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  // }
+UPB_END_EXTERN_C
 
 #ifdef __cplusplus
-// C++ implementation details. /////////////////////////////////////////////////
+/* C++ implementation details. ************************************************/
 namespace upb {
 namespace descriptor {
-inline Reader::Reader(const Handlers *h, Status *s) {
-  upb_descreader_init(this, h, s);
+inline Reader* Reader::Create(Environment* e, const Handlers *h) {
+  return upb_descreader_create(e, h);
 }
-inline Reader::~Reader() { upb_descreader_uninit(this); }
-inline void Reader::Reset() { upb_descreader_reset(this); }
 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
+}  /* namespace descriptor */
+}  /* namespace upb */
 #endif
 
-#endif  // UPB_DESCRIPTOR_H
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * Internal-only definitions for the decoder.
+#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 - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * upb::pb::Decoder implements 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.
- */
+** 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_
@@ -6755,293 +7056,194 @@
 class Decoder;
 class DecoderMethod;
 class DecoderMethodOptions;
-}  // namespace pb
-}  // namespace upb
+}  /* 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::DecoderMethod, upb_pbdecodermethod);
-UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts);
+UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache)
+UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder)
+UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts)
 
-// 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
+UPB_DECLARE_DERIVED_TYPE(upb::pb::DecoderMethod, upb::RefCounted,
+                         upb_pbdecodermethod, upb_refcounted)
 
-// Internal-only struct used by the decoder.
-typedef struct {
- UPB_PRIVATE_FOR_CPP
-  // 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;
+#ifdef __cplusplus
 
-  // 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;
-
-// The parameters one uses to construct a DecoderMethod.
-// TODO(haberman): move allowjit here?  Seems more convenient for users.
-UPB_DEFINE_CLASS0(upb::pb::DecoderMethodOptions,
+/* 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.
+  /* 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.
+  /* 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);
-,
-UPB_DEFINE_STRUCT0(upb_pbdecodermethodopts,
+#else
+struct upb_pbdecodermethodopts {
+#endif
   const upb_handlers *handlers;
   bool lazy;
-));
+};
 
-// Represents the code to parse a protobuf according to a destination Handlers.
-UPB_DEFINE_CLASS1(upb::pb::DecoderMethod, upb::RefCounted,
+#ifdef __cplusplus
+
+/* Represents the code to parse a protobuf according to a destination
+ * Handlers. */
+class upb::pb::DecoderMethod {
  public:
-  // From upb::ReferenceCounted.
-  void Ref(const void* owner) const;
-  void Unref(const void* owner) const;
-  void DonateRef(const void* from, const void* to) const;
-  void CheckRef(const void* owner) const;
+  /* 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.
+  /* 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.
+  /* The input handlers for this decoder method. */
   const BytesHandler* input_handler() const;
 
-  // Whether this method is native.
+  /* Whether this method is native. */
   bool is_native() const;
 
-  // Convenience method for generating a DecoderMethod without explicitly
-  // creating a CodeCache.
+  /* 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);
-,
-UPB_DEFINE_STRUCT(upb_pbdecodermethod, upb_refcounted,
-  // 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;
+  UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod)
+};
 
-  // 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;
+#endif
 
-  // Whether this method is native code or bytecode.
-  bool is_native_;
+/* 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
 
-  // The handler one calls to invoke this method.
-  upb_byteshandler input_handler_;
+#ifdef __cplusplus
 
-  // 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;
-));
-
-// A Decoder receives binary protobuf data on its input sink and pushes the
-// decoded data to its output sink.
-UPB_DEFINE_CLASS0(upb::pb::Decoder,
+/* 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.
-  Decoder(const DecoderMethod* method, Status* status);
-  ~Decoder();
+  /* 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.
-  // TODO(haberman): Do users need to be able to rebind this?
+  /* Returns the DecoderMethod this decoder is parsing from. */
   const DecoderMethod* method() const;
 
-  // Resets the state of the decoder.
-  void Reset();
-
-  // 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;
-
-  // Resets the output sink of the Decoder.
-  // The given sink must match method()->dest_handlers().
-  //
-  // This must be called at least once before the decoder can be used.  It may
-  // only be called with the decoder is in a state where it was just created or
-  // reset with pipeline.Reset().  The given sink must be from the same pipeline
-  // as this decoder.
-  bool ResetOutput(Sink* sink);
-
-  // The sink on which this decoder receives input.
+  /* 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_COPY_AND_ASSIGN(Decoder);
-,
-UPB_DEFINE_STRUCT0(upb_pbdecoder, UPB_QUOTE(
-  // Our input sink.
-  upb_bytessink input_;
+  UPB_DISALLOW_POD_OPS(Decoder, upb::pb::Decoder)
+};
 
-  // The decoder method we are parsing with (owned).
-  const upb_pbdecodermethod *method_;
+#endif  /* __cplusplus */
 
-  size_t call_len;
-  const uint32_t *pc, *last;
+#ifdef __cplusplus
 
-  // Current input buffer and its stream offset.
-  const char *buf, *ptr, *end, *checkpoint;
-
-  // End of the delimited region, relative to ptr, or NULL if not in this buf.
-  const char *delim_end;
-
-  // End of the delimited region, relative to ptr, or 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;
-
-  // Stores the user buffer passed to our decode function.
-  const char *buf_param;
-  size_t size_param;
-  const upb_bufhandle *handle;
-
-#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
-
-  upb_status *status;
-
-  // Our internal stack.
-  upb_pbdecoder_frame *top, *limit;
-  upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING];
-#ifdef UPB_USE_JIT_X64
-  // Each native stack frame needs two pointers, plus we need a few frames for
-  // the enter/exit trampolines.
-  const uint32_t *callstack[(UPB_DECODER_MAX_NESTING * 2) + 10];
-#else
-  const uint32_t *callstack[UPB_DECODER_MAX_NESTING];
-#endif
-)));
-
-// 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.
-UPB_DEFINE_CLASS0(upb::pb::CodeCache,
+/* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* 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);
-,
-UPB_DEFINE_STRUCT0(upb_pbcodecache,
+  UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache)
+#else
+struct upb_pbcodecache {
+#endif
   bool allow_jit_;
 
-  // Array of mgroups.
+  /* Array of mgroups. */
   upb_inttable groups;
-));
+};
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *method,
-                        upb_status *status);
-void upb_pbdecoder_uninit(upb_pbdecoder *d);
-void upb_pbdecoder_reset(upb_pbdecoder *d);
+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);
-bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink *sink);
 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);
 
-void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner);
-void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m, const void *owner);
-void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
-                                   const void *from, const void *to);
-void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
-                                  const void *owner);
+
+/* 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(
@@ -7057,7 +7259,7 @@
 const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
     upb_pbcodecache *c, const upb_pbdecodermethodopts *opts);
 
-UPB_END_EXTERN_C  // }
+UPB_END_EXTERN_C
 
 #ifdef __cplusplus
 
@@ -7065,27 +7267,27 @@
 
 namespace pb {
 
-inline Decoder::Decoder(const DecoderMethod* m, Status* s) {
-  upb_pbdecoder_init(this, m, s);
-}
-inline Decoder::~Decoder() {
-  upb_pbdecoder_uninit(this);
+/* 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 void Decoder::Reset() {
-  upb_pbdecoder_reset(this);
+inline BytesSink* Decoder::input() {
+  return upb_pbdecoder_input(this);
 }
 inline uint64_t Decoder::BytesParsed() const {
   return upb_pbdecoder_bytesparsed(this);
 }
-inline bool Decoder::ResetOutput(Sink* sink) {
-  return upb_pbdecoder_resetoutput(this, sink);
+inline size_t Decoder::max_nesting() const {
+  return upb_pbdecoder_maxnesting(this);
 }
-inline BytesSink* Decoder::input() {
-  return upb_pbdecoder_input(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);
@@ -7094,18 +7296,6 @@
   upb_pbdecodermethodopts_setlazy(this, lazy);
 }
 
-inline void DecoderMethod::Ref(const void *owner) const {
-  upb_pbdecodermethod_ref(this, owner);
-}
-inline void DecoderMethod::Unref(const void *owner) const {
-  upb_pbdecodermethod_unref(this, owner);
-}
-inline void DecoderMethod::DonateRef(const void *from, const void *to) const {
-  upb_pbdecodermethod_donateref(this, from, to);
-}
-inline void DecoderMethod::CheckRef(const void *owner) const {
-  upb_pbdecodermethod_checkref(this, owner);
-}
 inline const Handlers* DecoderMethod::dest_handlers() const {
   return upb_pbdecodermethod_desthandlers(this);
 }
@@ -7115,7 +7305,7 @@
 inline bool DecoderMethod::is_native() const {
   return upb_pbdecodermethod_isnative(this);
 }
-// static
+/* static */
 inline reffed_ptr<const DecoderMethod> DecoderMethod::New(
     const DecoderMethodOptions &opts) {
   const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m);
@@ -7139,33 +7329,44 @@
   return upb_pbcodecache_getdecodermethod(this, &opts);
 }
 
-}  // namespace pb
-}  // namespace upb
+}  /* namespace pb */
+}  /* namespace upb */
 
-#endif  // __cplusplus
+#endif  /* __cplusplus */
 
 #endif  /* UPB_DECODER_H_ */
 
-// 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.
+/* 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.
+  /* 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_STARTMSG       = 9,   /* No arg. */
+  OP_ENDMSG         = 10,  /* No arg. */
   OP_STARTSEQ       = 11,
   OP_ENDSEQ         = 12,
   OP_STARTSUBMSG    = 14,
@@ -7174,82 +7375,214 @@
   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 || groupnum (32) |
+  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,  // | expected tag (16) | jump target (8) | opc (8) |
-  OP_TAG2           = 33,  // | expected tag (16) | jump target (8) | opc (8) |
-  OP_TAGN           = 34,  // three words:
-                           //   | unused (16) | jump target(8) | opc (8) |
-                           //   |           expected tag 1 (32)          |
-                           //   |           expected tag 2 (32)          |
+  /* 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_SETDISPATCH    = 35,  /* N words: */
+                           /*   | unused (24)         | opc | */
+                           /*   | upb_inttable* (32 or 64)  | */
 
-  OP_DISPATCH       = 36,  // No arg.
+  OP_DISPATCH       = 36,  /* No arg. */
 
-  OP_HALT           = 37,  // 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
-//                +----------+
-typedef struct {
+/* 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.
+  /* 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.
+  /* 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.
+  /* 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.
+  /* JIT-generated machine code, if any. */
   upb_string_handlerfunc *jit_code;
-  // The size of the jit_code (required to munmap()).
+  /* The size of the jit_code (required to munmap()). */
   size_t jit_size;
   char *debug_info;
   void *dl;
 #endif
-} mgroup;
+};
 
-// Decoder entry points; used as handlers.
+/* 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.
+/* 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);
@@ -7261,41 +7594,43 @@
 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.
+/* 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.
+/* Access to decoderplan members needed by the decoder. */
 const char *upb_pbdecoder_getopname(unsigned int op);
 
-// JIT codegen entry point.
+/* 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."
+/* 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.
+/* 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).
+/* 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).
+/* 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;
@@ -7308,29 +7643,24 @@
   *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).
+/* 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 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_
+#endif  /* UPB_DECODER_INT_H_ */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * A number of routines for varint manipulation (we keep them all around to
- * have multiple approaches available for benchmarking).
- */
+** 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_
@@ -7343,25 +7673,25 @@
 extern "C" {
 #endif
 
-// A list of types as they are encoded on-the-wire.
+/* 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_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).
+/* 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).
+/* 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 **************************************************/
@@ -7377,44 +7707,59 @@
 
 /* Decoding *******************************************************************/
 
-// All decoding functions return this struct by value.
+/* All decoding functions return this struct by value. */
 typedef struct {
-  const char *p;  // NULL if the varint was unterminated.
+  const char *p;  /* NULL if the varint was unterminated. */
   uint64_t val;
 } upb_decoderet;
 
-// 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_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!
+/* 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;                                                   \
-  if ((*p & 0x80) == 0) { upb_decoderet r = {_p + 1, *p & 0x7fU}; return r; }  \
-  upb_decoderet r = {_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)};        \
-  if ((*(p + 1) & 0x80) == 0) return r;                                        \
+  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);
+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.
+/* 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);
@@ -7431,7 +7776,7 @@
 
 UPB_INLINE int upb_value_size(uint64_t val) {
 #ifdef __GNUC__
-  int high_bit = 63 - __builtin_clzll(val);  // 0-based, undef if val == 0.
+  int high_bit = 63 - __builtin_clzll(val);  /* 0-based, undef if val == 0. */
 #else
   int high_bit = 0;
   uint64_t tmp = val;
@@ -7440,13 +7785,14 @@
   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.
+/* 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; }
-  size_t i = 0;
+  i = 0;
   while (val) {
     uint8_t byte = val & 0x7fU;
     val >>= 7;
@@ -7461,7 +7807,7 @@
   return upb_vencode64(val, buf);
 }
 
-// Encodes a 32-bit varint, *not* sign-extended.
+/* 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);
@@ -7478,18 +7824,15 @@
 
 #endif  /* UPB_VARINT_DECODER_H_ */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009-2010 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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.
- */
+** 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_
@@ -7499,111 +7842,52 @@
 namespace upb {
 namespace pb {
 class Encoder;
-}  // namespace pb
-}  // namespace upb
+}  /* namespace pb */
+}  /* namespace upb */
 #endif
 
-UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder);
+UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder)
 
 #define UPB_PBENCODER_MAX_NESTING 100
 
 /* upb::pb::Encoder ***********************************************************/
 
-// 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 {
- UPB_PRIVATE_FOR_CPP
-  uint32_t msglen;  // The length to varint-encode before this segment.
-  uint32_t seglen;  // Length of the segment.
-} upb_pb_encoder_segment;
+/* 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
 
-UPB_DEFINE_CLASS0(upb::pb::Encoder,
+#ifdef __cplusplus
+
+class upb::pb::Encoder {
  public:
-  Encoder(const upb::Handlers* handlers);
-  ~Encoder();
+  /* 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);
 
-  static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* msg);
-
-  // Resets the state of the printer, so that it will expect to begin a new
-  // document.
-  void Reset();
-
-  // Resets the output pointer which will serve as our closure.
-  void ResetOutput(BytesSink* output);
-
-  // The input to the encoder.
+  /* 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_COPY_AND_ASSIGN(Encoder);
-,
-UPB_DEFINE_STRUCT0(upb_pb_encoder, UPB_QUOTE(
-  // Our input and output.
-  upb_sink input_;
-  upb_bytessink *output_;
+  UPB_DISALLOW_POD_OPS(Encoder, upb::pb::Encoder)
+};
 
-  // 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[UPB_PBENCODER_MAX_NESTING], *top, *stacklimit;
-
-  // Depth of startmsg/endmsg calls.
-  int depth;
-
-  // Initial buffers for the output buffer and segment buffer.  If we outgrow
-  // these we will dynamically allocate bigger ones.
-  char initbuf[256];
-  upb_pb_encoder_segment seginitbuf[32];
-)));
+#endif
 
 UPB_BEGIN_EXTERN_C
 
 const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
                                                const void *owner);
-void upb_pb_encoder_reset(upb_pb_encoder *e);
 upb_sink *upb_pb_encoder_input(upb_pb_encoder *p);
-void upb_pb_encoder_init(upb_pb_encoder *e, const upb_handlers *h);
-void upb_pb_encoder_resetoutput(upb_pb_encoder *e, upb_bytessink *output);
-void upb_pb_encoder_uninit(upb_pb_encoder *e);
+upb_pb_encoder* upb_pb_encoder_create(upb_env* e, const upb_handlers* h,
+                                      upb_bytessink* output);
 
 UPB_END_EXTERN_C
 
@@ -7611,17 +7895,9 @@
 
 namespace upb {
 namespace pb {
-inline Encoder::Encoder(const upb::Handlers* handlers) {
-  upb_pb_encoder_init(this, handlers);
-}
-inline Encoder::~Encoder() {
-  upb_pb_encoder_uninit(this);
-}
-inline void Encoder::Reset() {
-  upb_pb_encoder_reset(this);
-}
-inline void Encoder::ResetOutput(BytesSink* output) {
-  upb_pb_encoder_resetoutput(this, output);
+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);
@@ -7631,36 +7907,31 @@
   const Handlers* h = upb_pb_encoder_newhandlers(md, &h);
   return reffed_ptr<const Handlers>(h, &h);
 }
-}  // namespace pb
-}  // namespace upb
+}  /* namespace pb */
+}  /* namespace upb */
 
 #endif
 
 #endif  /* UPB_ENCODER_H_ */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011-2012 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * 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).
- */
+** 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
@@ -7671,23 +7942,23 @@
 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).
+/* 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.
+/* 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.
+/* 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.
+/* 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
@@ -7695,8 +7966,8 @@
 
 namespace upb {
 
-// All routines that load descriptors expect the descriptor to be a
-// FileDescriptorSet.
+/* 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);
@@ -7707,23 +7978,22 @@
   return upb_load_descriptor_into_symtab(s, str, len, status);
 }
 
-// Templated so it can accept both string and std::string.
+/* 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
+}  /* namespace upb */
 
 #endif
 
-#endif
+#endif  /* UPB_GLUE_H */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
+** upb::pb::TextPrinter (upb_textprinter)
+**
+** Handlers for writing to protobuf text format.
+*/
 
 #ifndef UPB_TEXT_H_
 #define UPB_TEXT_H_
@@ -7733,64 +8003,57 @@
 namespace upb {
 namespace pb {
 class TextPrinter;
-}  // namespace pb
-}  // namespace upb
+}  /* namespace pb */
+}  /* namespace upb */
 #endif
 
-UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter);
+UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter)
 
-UPB_DEFINE_CLASS0(upb::pb::TextPrinter,
+#ifdef __cplusplus
+
+class upb::pb::TextPrinter {
  public:
-  // The given handlers must have come from NewHandlers().  It must outlive the
-  // TextPrinter.
-  explicit TextPrinter(const upb::Handlers* handlers);
+  /* 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);
 
-  bool ResetOutput(BytesSink* output);
   Sink* input();
 
-  // If handler caching becomes a requirement we can add a code cache as in
-  // decoder.h
+  /* 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);
+};
 
- private:
-,
-UPB_DEFINE_STRUCT0(upb_textprinter,
-  upb_sink input_;
-  upb_bytessink *output_;
-  int indent_depth_;
-  bool single_line_;
-  void *subc;
-));
+#endif
 
-UPB_BEGIN_EXTERN_C  // {
+UPB_BEGIN_EXTERN_C
 
-// C API.
-void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h);
-void upb_textprinter_uninit(upb_textprinter *p);
-bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output);
+/* 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  // }
+UPB_END_EXTERN_C
 
 #ifdef __cplusplus
 
 namespace upb {
 namespace pb {
-inline TextPrinter::TextPrinter(const upb::Handlers* handlers) {
-  upb_textprinter_init(this, handlers);
+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 bool TextPrinter::ResetOutput(BytesSink* output) {
-  return upb_textprinter_resetoutput(this, output);
-}
 inline Sink* TextPrinter::input() {
   return upb_textprinter_input(this);
 }
@@ -7799,21 +8062,18 @@
   const Handlers* h = upb_textprinter_newhandlers(md, &h);
   return reffed_ptr<const Handlers>(h, &h);
 }
-}  // namespace pb
-}  // namespace upb
+}  /* namespace pb */
+}  /* namespace upb */
 
 #endif
 
 #endif  /* UPB_TEXT_H_ */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * upb::json::Parser can parse JSON according to a specific schema.
- * Support for parsing arbitrary JSON (schema-less) will be added later.
- */
+** 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_
@@ -7823,102 +8083,39 @@
 namespace upb {
 namespace json {
 class Parser;
-}  // namespace json
-}  // namespace upb
+}  /* namespace json */
+}  /* namespace upb */
 #endif
 
-UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser);
-
-// Internal-only struct used by the parser. A parser frame corresponds
-// one-to-one with a handler (sink) frame.
-typedef struct {
- UPB_PRIVATE_FOR_CPP
-  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;
-
+UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser)
 
 /* upb::json::Parser **********************************************************/
 
-#define UPB_JSON_MAX_DEPTH 64
+/* 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
 
-// Parses an incoming BytesStream, pushing the results to the destination sink.
-UPB_DEFINE_CLASS0(upb::json::Parser,
+#ifdef __cplusplus
+
+/* Parses an incoming BytesStream, pushing the results to the destination
+ * sink. */
+class upb::json::Parser {
  public:
-  Parser(Status* status);
-  ~Parser();
+  static Parser* Create(Environment* env, Sink* output);
 
-  // Resets the state of the printer, so that it will expect to begin a new
-  // document.
-  void Reset();
-
-  // Resets the output pointer which will serve as our closure.  Implies
-  // Reset().
-  void ResetOutput(Sink* output);
-
-  // The input to the printer.
   BytesSink* input();
-,
-UPB_DEFINE_STRUCT0(upb_json_parser,
-  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;
+ private:
+  UPB_DISALLOW_POD_OPS(Parser, upb::json::Parser)
+};
 
-  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;
-));
+#endif
 
 UPB_BEGIN_EXTERN_C
 
-void upb_json_parser_init(upb_json_parser *p, upb_status *status);
-void upb_json_parser_uninit(upb_json_parser *p);
-void upb_json_parser_reset(upb_json_parser *p);
-void upb_json_parser_resetoutput(upb_json_parser *p, upb_sink *output);
+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
@@ -7927,31 +8124,24 @@
 
 namespace upb {
 namespace json {
-inline Parser::Parser(Status* status) { upb_json_parser_init(this, status); }
-inline Parser::~Parser() { upb_json_parser_uninit(this); }
-inline void Parser::Reset() { upb_json_parser_reset(this); }
-inline void Parser::ResetOutput(Sink* output) {
-  upb_json_parser_resetoutput(this, output);
+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
+}  /* namespace json */
+}  /* namespace upb */
 
 #endif
 
 
-#endif  // UPB_JSON_PARSER_H_
+#endif  /* UPB_JSON_PARSER_H_ */
 /*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2014 Google Inc.  See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * upb::json::Printer allows you to create handlers that emit JSON
- * according to a specific protobuf schema.
- */
+** 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_
@@ -7961,80 +8151,57 @@
 namespace upb {
 namespace json {
 class Printer;
-}  // namespace json
-}  // namespace upb
+}  /* namespace json */
+}  /* namespace upb */
 #endif
 
-UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer);
+UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer)
 
 
 /* upb::json::Printer *********************************************************/
 
-// Prints an incoming stream of data to a BytesSink in JSON format.
-UPB_DEFINE_CLASS0(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:
-  Printer(const upb::Handlers* handlers);
-  ~Printer();
+  static Printer* Create(Environment* env, const upb::Handlers* handlers,
+                         BytesSink* output);
 
-  // Resets the state of the printer, so that it will expect to begin a new
-  // document.
-  void Reset();
-
-  // Resets the output pointer which will serve as our closure.  Implies
-  // Reset().
-  void ResetOutput(BytesSink* output);
-
-  // The input to the printer.
+  /* The input to the printer. */
   Sink* input();
 
-  // Returns handlers for printing according to the specified schema.
+  /* Returns handlers for printing according to the specified schema. */
   static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md);
-,
-UPB_DEFINE_STRUCT0(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];
-));
+  static const size_t kSize = UPB_JSON_PRINTER_SIZE;
 
-UPB_BEGIN_EXTERN_C  // {
+ private:
+  UPB_DISALLOW_POD_OPS(Printer, upb::json::Printer)
+};
 
-// Native C API.
+#endif
 
-void upb_json_printer_init(upb_json_printer *p, const upb_handlers *h);
-void upb_json_printer_uninit(upb_json_printer *p);
-void upb_json_printer_reset(upb_json_printer *p);
-void upb_json_printer_resetoutput(upb_json_printer *p, upb_bytessink *output);
+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  // }
+UPB_END_EXTERN_C
 
 #ifdef __cplusplus
 
 namespace upb {
 namespace json {
-inline Printer::Printer(const upb::Handlers* handlers) {
-  upb_json_printer_init(this, handlers);
-}
-inline Printer::~Printer() { upb_json_printer_uninit(this); }
-inline void Printer::Reset() { upb_json_printer_reset(this); }
-inline void Printer::ResetOutput(BytesSink* output) {
-  upb_json_printer_resetoutput(this, output);
+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(
@@ -8042,9 +8209,9 @@
   const Handlers* h = upb_json_printer_newhandlers(md, &h);
   return reffed_ptr<const Handlers>(h, &h);
 }
-}  // namespace json
-}  // namespace upb
+}  /* namespace json */
+}  /* namespace upb */
 
 #endif
 
-#endif  // UPB_JSON_TYPED_PRINTER_H_
+#endif  /* UPB_JSON_TYPED_PRINTER_H_ */
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index 371009b..7b64ee7 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -1,24 +1,25 @@
-class << Gem::Specification
-  def find_c_source(dir)
-    `cd #{dir}; git ls-files "*.c" "*.h" extconf.rb Makefile`.split
-    .map{|f| "#{dir}/#{f}"}
-  end
-end
-
 Gem::Specification.new do |s|
   s.name        = "google-protobuf"
-  s.version     = "3.0.0.alpha.3.0.pre"
+  s.version     = "3.0.0.alpha.5.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.extensions  = ["ext/google/protobuf_c/extconf.rb"]
-  s.files       = ["lib/google/protobuf.rb"] +
-                  # extension C source
-                  find_c_source("ext/google/protobuf_c")
-  s.test_files = ["tests/basic.rb",
-		  "tests/stress.rb",
-		  "tests/generated_code_test.rb"]
+  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
index 7405333..62bdd1b 100644
--- a/ruby/lib/google/protobuf.rb
+++ b/ruby/lib/google/protobuf.rb
@@ -28,4 +28,49 @@
 # (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 'google/protobuf_c'
+# 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..16c843c
--- /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, :combination, :compact, :count, :cycle,
+        :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
index a78cc39..da85520 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -8,6 +8,19 @@
 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
@@ -84,6 +97,9 @@
     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
@@ -138,6 +154,8 @@
       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
@@ -160,7 +178,7 @@
                           :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 m.inspect == expected
+      assert_equal expected, m.inspect
     end
 
     def test_hash
@@ -173,6 +191,35 @@
       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
@@ -258,7 +305,7 @@
 
       assert l.inspect == '[5, 2, 3, 4]'
 
-      l.insert(7, 8, 9)
+      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]
@@ -298,6 +345,17 @@
       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
@@ -361,6 +419,39 @@
       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.
@@ -696,9 +787,12 @@
       m = TestMessage.new
       m.optional_string = "hello"
       m.optional_int32 = 42
-      m.repeated_msg.push TestMessage2.new(:foo => 100)
-      m.repeated_msg.push TestMessage2.new(:foo => 200)
-
+      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
@@ -757,6 +851,67 @@
       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
@@ -811,7 +966,6 @@
       assert m['a.b'] == 4
     end
 
-
     def test_int_ranges
       m = TestMessage.new
 
@@ -917,7 +1071,6 @@
       assert_raise RangeError do
         m.optional_uint64 = 1.5
       end
-
     end
 
     def test_stress_test
@@ -972,6 +1125,8 @@
     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,
@@ -991,9 +1146,19 @@
       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 = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
       assert MapMessage.encode_json(m) == expected
diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto
index b1d6323..42d82a6 100644
--- a/ruby/tests/generated_code.proto
+++ b/ruby/tests/generated_code.proto
@@ -3,17 +3,17 @@
 package A.B.C;
 
 message TestMessage {
-  optional int32 optional_int32 = 1;
-  optional int64 optional_int64 = 2;
-  optional uint32 optional_uint32 = 3;
-  optional uint64 optional_uint64 = 4;
-  optional bool optional_bool = 5;
-  optional double optional_double = 6;
-  optional float optional_float = 7;
-  optional string optional_string = 8;
-  optional bytes optional_bytes = 9;
-  optional TestEnum optional_enum = 10;
-  optional TestMessage optional_msg = 11;
+  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;
@@ -53,10 +53,10 @@
   map<string, bool> map_string_bool = 70;
 
   message NestedMessage {
-    optional int32 foo = 1;
+    int32 foo = 1;
   }
 
-  optional NestedMessage nested_message = 80;
+  NestedMessage nested_message = 80;
 }
 
 enum TestEnum {
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
index 1bd768e..082d5e2 100644
--- a/ruby/tests/stress.rb
+++ b/ruby/tests/stress.rb
@@ -30,7 +30,7 @@
       100_000.times do
         mnew = TestMessage.decode(data)
         mnew = mnew.dup
-        assert mnew.inspect == m.inspect
+        assert_equal mnew.inspect, m.inspect
         assert TestMessage.encode(mnew) == data
       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 63a1451..073673a 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,37 +32,34 @@
 # 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.
 clean-local:
 	rm -f *.loT
 
-public_config = google/protobuf/stubs/pbconfig.h
-
-CLEANFILES = $(protoc_outputs) $(public_config) unittest_proto_middleman \
+CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
              testzip.jar testzip.list testzip.proto testzip.zip
 
 MAINTAINERCLEANFILES =   \
   Makefile.in
 
-# Generate and distribute a minimum config.h file to make hash_map work.
-# The autoheader config has too much info, which might conflict with other
-# macros applications might include. Thus, we create a stubs/pbconfig.h, that
-# only #defines what we really need, and prefix it with GOOGLE_PROTOBUF_ to
-# avoid conflicts.
-$(public_config): $(top_builddir)/config.h $(top_srcdir)/config.h.include
-	echo "// Note: Google Protobuf internal only. Do NOT include." > $@
-	cat $(top_builddir)/config.h | grep -f $(top_srcdir)/config.h.include | \
-	sed 's,#define , #define GOOGLE_PROTOBUF_,' >> $@
-
 nobase_include_HEADERS =                                        \
   google/protobuf/stubs/atomic_sequence_num.h                   \
   google/protobuf/stubs/atomicops.h                             \
-  google/protobuf/stubs/atomicops_internals_aix.h               \
+  google/protobuf/stubs/atomicops_internals_power.h             \
   google/protobuf/stubs/atomicops_internals_arm64_gcc.h         \
-  google/protobuf/stubs/atomicops_internals_tile_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 \
@@ -66,24 +71,39 @@
   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/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/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_enum_util.h                         \
   google/protobuf/generated_message_reflection.h                \
@@ -91,8 +111,8 @@
   google/protobuf/map_entry.h                                   \
   google/protobuf/map_entry_lite.h                              \
   google/protobuf/map_field.h                                   \
-  google/protobuf/map_field_lite.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                                     \
@@ -103,11 +123,16 @@
   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                                  \
@@ -123,14 +148,23 @@
   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/java/java_names.h                    \
   google/protobuf/compiler/javanano/javanano_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
-
-nobase_nodist_include_HEADERS =                                 \
-  $(public_config)
+  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
 
@@ -139,13 +173,30 @@
 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                             \
@@ -157,38 +208,89 @@
   google/protobuf/io/coded_stream_inl.h                        \
   google/protobuf/io/zero_copy_stream.cc                       \
   google/protobuf/io/zero_copy_stream_impl_lite.cc
-nodist_libprotobuf_lite_la_SOURCES = $(public_config)
 
 libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
 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_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
@@ -231,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_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                   \
@@ -247,24 +355,41 @@
   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_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/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     \
@@ -288,8 +413,62 @@
   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/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_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
@@ -297,32 +476,49 @@
 
 # Tests ==============================================================
 
-protoc_inputs =                                                \
-  google/protobuf/map_lite_unittest.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_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_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_enum.proto         \
-  google/protobuf/unittest_preserve_unknown_enum2.proto        \
-  google/protobuf/unittest_proto3_arena.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_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)                                             \
@@ -334,6 +530,7 @@
   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             \
@@ -342,66 +539,101 @@
   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/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.pb.cc                               \
-  google/protobuf/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_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_no_arena.pb.cc                      \
-  google/protobuf/unittest_no_arena.pb.h                       \
-  google/protobuf/unittest_no_arena_import.pb.cc               \
-  google/protobuf/unittest_no_arena_import.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_preserve_unknown_enum.pb.cc         \
-  google/protobuf/unittest_preserve_unknown_enum.pb.h          \
-  google/protobuf/unittest_preserve_unknown_enum2.pb.cc        \
-  google/protobuf/unittest_preserve_unknown_enum2.pb.h         \
-  google/protobuf/unittest_proto3_arena.pb.cc                  \
-  google/protobuf/unittest_proto3_arena.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_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 = $(public_config) $(protoc_outputs)
+BUILT_SOURCES = $(protoc_outputs)
 
 if USE_EXTERNAL_PROTOC
 
@@ -436,24 +668,33 @@
   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              \
@@ -473,6 +714,7 @@
   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                       \
@@ -487,20 +729,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 =                        \
@@ -508,24 +768,44 @@
   $(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                                     \
+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
-  # TODO(teboring) add the file back and make the test build.
-  # google/protobuf/map_lite_test.cc
+
+# 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                                     \
+  $(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                              \
@@ -541,4 +821,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/README.md b/src/README.md
new file mode 100644
index 0000000..4e312c0
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,209 @@
+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)
+
+On Ubuntu, you can install them with:
+
+  $ sudo apt-get install autoconf automake libtool curl
+
+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.
+
+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..f3ca06b
--- /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) {
+  return string(kTypeGoogleApisComPrefix) + 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) {
+  type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
+                        GetTypeUrl(message.GetDescriptor()));
+  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());
+  const string full_name = descriptor->full_name();
+  if (type_url.length() < full_name.length()) {
+      return false;
+  }
+  return (0 == type_url.compare(
+    type_url.length() - full_name.length(),
+    full_name.length(),
+    full_name));
+}
+
+bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
+  static const char* prefix[] = {
+    kTypeGoogleApisComPrefix,
+    kTypeGoogleProdComPrefix
+  };
+  for (int i = 0; i < 2; i++) {
+    const int prefix_len = strlen(prefix[i]);
+    if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) {
+      full_type_name->assign(type_url.data() + prefix_len,
+                             type_url.size() - prefix_len);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+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..c8dbef1
--- /dev/null
+++ b/src/google/protobuf/any.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_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);
+
+  void PackFrom(const Message& message);
+
+  bool UnpackTo(Message* message) const;
+
+  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..0bf523b
--- /dev/null
+++ b/src/google/protobuf/any.pb.cc
@@ -0,0 +1,483 @@
+// 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(\014BK\n\023com.google.protobufB\010AnyProtoP\001\240"
+    "\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownType"
+    "sb\006proto3", 169);
+  ::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);
+}
+
+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() {
+  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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Any* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Any>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Any::MergeFrom(const Any& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Any::CopyFrom(const Any& from) {
+  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() {
+  
+  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() {
+  
+  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..97982ec
--- /dev/null
+++ b/src/google/protobuf/any.pb.h
@@ -0,0 +1,250 @@
+// 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);
+  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() {
+  
+  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() {
+  
+  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
index bf2aa0a..e8a18bc 100644
--- a/src/google/protobuf/any.proto
+++ b/src/google/protobuf/any.proto
@@ -27,22 +27,24 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (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 java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "AnyProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 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 message along with a URL
 // that describes the type of the serialized message.
 //
 //
-//
-// # JSON
+// 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:
@@ -61,8 +63,8 @@
 //
 // 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 the `@type`
-// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
+// `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",
@@ -76,21 +78,20 @@
   // 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.
+  // * 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`).
-  // * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
+  // * 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 need to be preserved
+  //   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 valid serialized data of the above specified type.
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..e589a89
--- /dev/null
+++ b/src/google/protobuf/api.pb.cc
@@ -0,0 +1,1983 @@
+// 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() {
+  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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Api* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Api>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Api::MergeFrom(const Api& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Api::CopyFrom(const Api& from) {
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  ::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() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Method*>(16)->f)
+
+#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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Method* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Method>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Method::MergeFrom(const Method& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Method::CopyFrom(const Method& from) {
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool Mixin::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Mixin* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Mixin>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Mixin::MergeFrom(const Mixin& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Mixin::CopyFrom(const Mixin& from) {
+  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() {
+  
+  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() {
+  
+  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..e1dca4e
--- /dev/null
+++ b/src/google/protobuf/api.pb.h
@@ -0,0 +1,976 @@
+// 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() {
+  
+  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() {
+  
+  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() {
+  
+  ::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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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
index bda3741..cd0b21a 100755
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -38,7 +38,13 @@
 namespace protobuf {
 
 google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
-#ifdef PROTOBUF_USE_DLLS
+#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_;
@@ -55,13 +61,20 @@
   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;
-    first_block->owner = &first_block->owner;
-    AddBlock(first_block);
+    // 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;
   }
 
@@ -74,7 +87,7 @@
 }
 
 Arena::~Arena() {
-  uint64 space_allocated = Reset();
+  uint64 space_allocated = ResetInternal();
 
   // Call the destruction hook
   if (options_.on_arena_destruction != NULL) {
@@ -83,10 +96,14 @@
 }
 
 uint64 Arena::Reset() {
-  CleanupList();
-  uint64 space_allocated = FreeBlocks();
   // 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) {
@@ -131,6 +148,10 @@
 
 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) {
@@ -148,10 +169,16 @@
             reinterpret_cast<google::protobuf::internal::AtomicWord>(node)));
 }
 
-void* Arena::AllocateAligned(size_t n) {
+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.
@@ -169,16 +196,6 @@
   void* me = &thread_cache();
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
   if (!b || b->owner != me || b->avail() < n) {
-    // If the next block to allocate from is the first block, try to claim it
-    // for this thread.
-    if (!owns_first_block_ && b->next == NULL) {
-      MutexLock l(&blocks_lock_);
-      if (b->owner == &b->owner && b->avail() >= n) {
-        b->owner = me;
-        SetThreadCacheBlock(b);
-        return AllocFromBlock(b, n);
-      }
-    }
     return SlowAlloc(n);
   }
   return AllocFromBlock(b, n);
@@ -255,8 +272,12 @@
     // Make the first block that was passed in through ArenaOptions
     // available for reuse.
     first_block->pos = kHeaderSize;
-    first_block->owner = &first_block->owner;
-    AddBlock(first_block);
+    // 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;
 }
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index bb15e80..5ad94fa 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -28,17 +28,32 @@
 // (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 logically internal, but is made public because it is used
-// from protocol-compiler-generated code, which may reside in other components.
-
 #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 {
@@ -61,7 +76,7 @@
 template<typename T> void arena_delete_object(void* object) {
   delete reinterpret_cast<T*>(object);
 }
-inline void arena_free(void* object, size_t size) {
+inline void arena_free(void* object, size_t /* size */) {
   free(object);
 }
 
@@ -113,10 +128,13 @@
   void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
   void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
 
-  // type_name is promised to be a static string - its lifetime extends to
-  // match program's lifetime.
-  void (*on_arena_allocation)(const char* type_name, uint64 alloc_size,
-      Arena* arena, void* cookie);
+  // 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),
@@ -137,6 +155,14 @@
   static const size_t kDefaultMaxBlockSize   = 8192;
 };
 
+// Support for non-RTTI environments. (The metrics hooks API uses type
+// information.)
+#ifndef GOOGLE_PROTOBUF_NO_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
@@ -146,6 +172,44 @@
 // 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.
 class LIBPROTOBUF_EXPORT Arena {
  public:
   // Arena constructor taking custom options. See ArenaOptions below for
@@ -172,8 +236,10 @@
   // compilation error will occur.
   //
   // RepeatedField and RepeatedPtrField may also be instantiated directly on an
-  // arena with this method: they act as "arena-capable message types" for the
-  // purposes of the Arena API.
+  // 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) {
@@ -183,17 +249,55 @@
     }
   }
 
+  // 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>(
-          SkipDeleteList<T>(static_cast<T*>(0)));
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value);
     }
   }
 
@@ -203,7 +307,7 @@
     if (arena == NULL) {
       return new T(arg);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
                                       arg);
     }
   }
@@ -214,9 +318,8 @@
     if (arena == NULL) {
       return new T(arg1, arg2);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
-                                      arg1,
-                                      arg2);
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2);
     }
   }
 
@@ -229,10 +332,8 @@
     if (arena == NULL) {
       return new T(arg1, arg2, arg3);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
-                                      arg1,
-                                      arg2,
-                                      arg3);
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3);
     }
   }
 
@@ -246,20 +347,92 @@
     if (arena == NULL) {
       return new T(arg1, arg2, arg3, arg4);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
-                                      arg1,
-                                      arg2,
-                                      arg3,
-                                      arg4);
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4);
     }
   }
 
-  // Create an array of object type T on the arena. Type T must have a trivial
-  // constructor, as it will not be invoked when created on the arena.
+  // 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 new T[num_elements];
+      return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
     } else {
       return arena->CreateInternalRawArray<T>(num_elements);
     }
@@ -269,16 +442,16 @@
   // 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.
-  uint64 SpaceAllocated() const GOOGLE_ATTRIBUTE_NOINLINE;
+  GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceAllocated() const;
   // As above, but does not include any free space in underlying blocks.
-  uint64 SpaceUsed() const GOOGLE_ATTRIBUTE_NOINLINE;
+  GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceUsed() 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.
-  uint64 Reset() GOOGLE_ATTRIBUTE_NOINLINE;
+  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.
@@ -303,8 +476,8 @@
   // 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.
-  void OwnCustomDestructor(void* object, void (*destruct)(void*))
-      GOOGLE_ATTRIBUTE_NOINLINE {
+  GOOGLE_ATTRIBUTE_NOINLINE void OwnCustomDestructor(void* object,
+                                              void (*destruct)(void*)) {
     AddListNode(object, destruct);
   }
 
@@ -313,31 +486,32 @@
   // 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 inline ::google::protobuf::Arena* GetArena(const T* value) {
+  static ::google::protobuf::Arena* GetArena(const T* value) {
     return GetArenaInternal(value, static_cast<T*>(0));
   }
 
-  // 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 an instance of
-  // google::protobuf::internal::true_type if the message type T has arena support enabled, and
-  // google::protobuf::internal::false_type 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 {
+ private:
+  struct InternalIsArenaConstructableHelper {
     template<typename U>
     static char ArenaConstructable(
         const typename U::InternalArenaConstructable_*);
     template<typename U>
     static double ArenaConstructable(...);
+  };
 
-    // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
-    typedef google::protobuf::internal::integral_constant<bool,
-              sizeof(ArenaConstructable<const T>(static_cast<const T*>(0))) ==
-              sizeof(char)> type;
-    static const type value;
+ 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:
@@ -351,7 +525,7 @@
     // aligned at a multiple of 8 bytes.
     size_t pos;
     size_t size;  // total size of the block.
-    size_t avail() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { return size - pos; }
+    GOOGLE_ATTRIBUTE_ALWAYS_INLINE size_t avail() const { return size - pos; }
     // data follows
   };
 
@@ -369,7 +543,12 @@
 
   static const size_t kHeaderSize = sizeof(Block);
   static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
-#ifdef PROTOBUF_USE_DLLS
+#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();
@@ -378,23 +557,47 @@
   static ThreadCache& thread_cache() { return thread_cache_; }
 #endif
 
-  // SFINAE for skipping addition to delete list for a Type. 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>.
-  //
+  // 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 non message objects, we skip addition to delete list if the object has
-  // a trivial destructor.
+  // 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
@@ -414,14 +617,17 @@
   // Just allocate the required size for the given type assuming the
   // type has a trivial constructor.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateInternalRawArray(uint32 num_elements) {
-    return static_cast<T*>(AllocateAligned(sizeof(T) * num_elements));
+  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
-  inline T* CreateInternal(
-      bool skip_explicit_ownership) {
-    T* t = new (AllocateAligned(sizeof(T))) T();
+  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>);
     }
@@ -429,9 +635,8 @@
   }
 
   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateInternal(
-      bool skip_explicit_ownership, const Arg& arg) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg);
+  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>);
     }
@@ -439,9 +644,9 @@
   }
 
   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateInternal(
+  T* CreateInternal(
       bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg1, 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>);
     }
@@ -449,11 +654,12 @@
   }
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3>
-  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
-                                                   const Arg1& arg1,
-                                                   const Arg2& arg2,
-                                                   const Arg3& arg3) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, 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>);
     }
@@ -462,12 +668,84 @@
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
             typename Arg4>
-  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
-                                                   const Arg1& arg1,
-                                                   const Arg2& arg2,
-                                                   const Arg3& arg3,
-                                                   const Arg4& arg4) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3, 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>);
     }
@@ -475,30 +753,56 @@
   }
 
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
+  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, is_arena_constructable<T>::value);
+    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* arena, google::protobuf::internal::false_type) {
     new (ptr) T;
   }
 
+  template <typename T>
+  static void RegisterDestructorInternal(
+      T* ptr, Arena* 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
@@ -521,18 +825,25 @@
   // InternalArenaConstructable_ tags can be associated with an arena, and such
   // objects must implement a GetArenaNoVirtual() method.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  static inline ::google::protobuf::Arena* GetArenaInternal(const T* value,
-      typename T::InternalArenaConstructable_*) {
+  static ::google::protobuf::Arena* GetArenaInternal(
+      const T* value, typename T::InternalArenaConstructable_*) {
     return value->GetArenaNoVirtual();
   }
 
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
+  static ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
     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);
 
-  void* AllocateAligned(size_t size);
+  // Allocate an internal allocation, avoiding optional typed monitoring.
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* AllocateAligned(size_t n) {
+    return AllocateAligned(NULL, n);
+  }
 
   void Init();
 
@@ -548,6 +859,7 @@
   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;
@@ -574,6 +886,9 @@
   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,
@@ -591,10 +906,8 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
 };
 
-template<typename T>
-const typename Arena::is_arena_constructable<T>::type
-    Arena::is_arena_constructable<T>::value =
-        typename Arena::is_arena_constructable<T>::type();
+// Defined above for supporting environments without RTTI.
+#undef RTTI_TYPE_ID
 
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py
index 41b1b5f..87a69b2 100644
--- a/src/google/protobuf/arena_nc_test.py
+++ b/src/google/protobuf/arena_nc_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,11 +32,13 @@
 
 """Negative compilation unit tests for arena API."""
 
+import unittest
+
 from google3.testing.pybase import fake_target_util
-from google.apputils import basetest
+import unittest
 
 
-class ArenaNcTest(basetest.TestCase):
+class ArenaNcTest(unittest.TestCase):
 
   def testCompilerErrors(self):
     """Runs a list of tests to verify compiler error messages."""
@@ -56,4 +58,4 @@
         )
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/src/google/protobuf/arena_test_util.cc b/src/google/protobuf/arena_test_util.cc
index 21f55c6..df9c5bd 100644
--- a/src/google/protobuf/arena_test_util.cc
+++ b/src/google/protobuf/arena_test_util.cc
@@ -28,6 +28,7 @@
 // (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>
 
diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h
index 7db7a90..690cc70 100644
--- a/src/google/protobuf/arena_test_util.h
+++ b/src/google/protobuf/arena_test_util.h
@@ -31,6 +31,7 @@
 #ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
 #define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
 
+
 namespace google {
 namespace protobuf {
 namespace internal {
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index d9b198e..6b67f44 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -30,8 +30,6 @@
 
 #include <google/protobuf/arena.h>
 
-#include <stdint.h>
-
 #include <algorithm>
 #include <cstring>
 #include <memory>
@@ -39,19 +37,25 @@
 #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>
 
@@ -125,6 +129,29 @@
   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) {
@@ -156,7 +183,7 @@
   EXPECT_EQ(2, notifier.GetCount());
 }
 
-TEST(ArenaTest, CreateWithManyConstructorArguments) {
+TEST(ArenaTest, CreateWithFourConstructorArguments) {
   Arena arena;
   const string three("3");
   const PleaseDontCopyMe four(4);
@@ -170,6 +197,26 @@
   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
@@ -315,7 +362,7 @@
   Arena arena;
   TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
   arena_message->mutable_optional_nested_message()->set_bb(118);
-  scoped_ptr<TestAllTypes::NestedMessage> nested(
+  google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested(
       arena_message->release_optional_nested_message());
   EXPECT_EQ(118, nested->bb());
 
@@ -336,7 +383,7 @@
   Arena arena;
   TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
   arena_message->set_optional_string("hello");
-  scoped_ptr<string> released_str(
+  google::protobuf::scoped_ptr<string> released_str(
       arena_message->release_optional_string());
   EXPECT_EQ("hello", *released_str);
 
@@ -574,8 +621,6 @@
   }
 }
 
-// N.B.: no reflection version of this test because all the arena-specific code
-// is in RepeatedPtrField, and the reflection works implicitly based on that.
 TEST(ArenaTest, AddAllocatedToRepeatedField) {
   // Heap->arena case.
   Arena arena1;
@@ -635,6 +680,55 @@
   }
 }
 
+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.
@@ -1113,6 +1207,19 @@
   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.
@@ -1124,6 +1231,13 @@
     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;
@@ -1141,10 +1255,12 @@
 
   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;
@@ -1153,6 +1269,7 @@
 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;
 
@@ -1160,7 +1277,13 @@
   {
     ::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);
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
index d829ed9..e2e2f25 100755
--- a/src/google/protobuf/arenastring.h
+++ b/src/google/protobuf/arenastring.h
@@ -33,9 +33,9 @@
 
 #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>
 
@@ -64,7 +64,7 @@
   }
 
   // Basic accessors.
-  inline const ::std::string& Get(const ::std::string* default_value) const {
+  inline const ::std::string& Get(const ::std::string* /* default_value */) const {
     return *ptr_;
   }
 
@@ -102,7 +102,7 @@
   // 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) {
+                                      ::google::protobuf::Arena* /* arena */) {
     if (ptr_ == default_value) {
       return NULL;
     }
@@ -134,7 +134,7 @@
   // 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) {
+                                      ::std::string* value, ::google::protobuf::Arena* /* arena */) {
     if (value != NULL) {
       ptr_ = value;
     } else {
@@ -145,7 +145,7 @@
   // 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.
-  inline void Swap(ArenaStringPtr* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
     std::swap(ptr_, other->ptr_);
   }
 
@@ -163,7 +163,7 @@
   // 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) {
+                           ::google::protobuf::Arena* /* arena */) {
     if (ptr_ == default_value) {
       // Already set to default (which is empty) -- do nothing.
     } else {
@@ -175,7 +175,7 @@
   // 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) {
+                             ::google::protobuf::Arena* /* arena */) {
     if (ptr_ == default_value) {
       // Already set to default -- do nothing.
     } else {
@@ -215,7 +215,7 @@
 
   void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
 
-  inline const ::std::string& GetNoArena(const ::std::string* default_value) const {
+  inline const ::std::string& GetNoArena(const ::std::string* /* default_value */) const {
     return *ptr_;
   }
 
@@ -283,9 +283,8 @@
  private:
   ::std::string* ptr_;
 
-  inline void CreateInstance(::google::protobuf::Arena* arena,
-                             const ::std::string* initial_value)
-      GOOGLE_ATTRIBUTE_NOINLINE {
+  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);
@@ -296,8 +295,7 @@
       arena->Own(ptr_);
     }
   }
-  inline void CreateInstanceNoArena(const ::std::string* initial_value)
-      GOOGLE_ATTRIBUTE_NOINLINE {
+  GOOGLE_ATTRIBUTE_NOINLINE void CreateInstanceNoArena(const ::std::string* initial_value) {
     if (initial_value != NULL) {
       ptr_ = new ::std::string(*initial_value);
     } else {
diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc
index 8ebd4b9..3fb582b 100644
--- a/src/google/protobuf/arenastring_unittest.cc
+++ b/src/google/protobuf/arenastring_unittest.cc
@@ -42,6 +42,7 @@
 #endif
 #include <cstdlib>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <gtest/gtest.h>
 
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 0910631..3a816b0 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>
@@ -48,12 +49,19 @@
 #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>
 #include <google/protobuf/compiler/importer.h>
@@ -67,6 +75,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>
@@ -182,6 +191,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.
@@ -195,15 +276,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)) {
-      std::cerr << dfile;
+      out << dfile;
     } else {
-      std::cerr << filename;
+      out << filename;
     }
 
     // Users typically expect 1-based line/column numbers, so we add 1
@@ -212,24 +313,22 @@
       // Allow for both GCC- and Visual-Studio-compatible output.
       switch (format_) {
         case CommandLineInterface::ERROR_FORMAT_GCC:
-          std::cerr << ":" << (line + 1) << ":" << (column + 1);
+          out << ":" << (line + 1) << ":" << (column + 1);
           break;
         case CommandLineInterface::ERROR_FORMAT_MSVS:
-          std::cerr << "(" << (line + 1)
-                    << ") : error in column=" << (column + 1);
+          out << "(" << (line + 1) << ") : "
+              << type << " in column=" << (column + 1);
           break;
       }
     }
 
-    std::cerr << ": " << message << std::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_;
 };
@@ -255,6 +354,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);
@@ -442,6 +544,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);
@@ -634,6 +744,8 @@
       break;
   }
 
+  AddDefaultProtoPaths(&proto_path_);
+
   // Set up the source tree.
   DiskSourceTree source_tree;
   for (int i = 0; i < proto_path_.size(); i++) {
@@ -673,7 +785,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.
@@ -720,6 +831,13 @@
     }
   }
 
+  if (!dependency_out_name_.empty()) {
+    if (!GenerateDependencyManifestFile(parsed_files, output_directories,
+                                        &source_tree)) {
+      return 1;
+    }
+  }
+
   STLDeleteValues(&output_directories);
 
   if (!descriptor_set_name_.empty()) {
@@ -778,6 +896,7 @@
   output_directives_.clear();
   codec_type_.clear();
   descriptor_set_name_.clear();
+  dependency_out_name_.clear();
 
   mode_ = MODE_COMPILE;
   print_mode_ = PRINT_NONE;
@@ -880,6 +999,17 @@
     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()) {
     std::cerr << "--include_imports only makes sense when combined with "
                  "--descriptor_set_out." << std::endl;
@@ -1026,6 +1156,17 @@
     }
     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_) {
       std::cerr << name << " may only be passed once." << std::endl;
@@ -1225,6 +1366,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"
@@ -1232,7 +1376,8 @@
 "                              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."  << std::endl;
+"                              occupied fields numbers.\n"
+      << std::endl;
   if (!plugin_prefix_.empty()) {
     std::cerr <<
 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
@@ -1287,14 +1432,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.
-        std::cerr << output_directive.name << ": " << parsed_files[i]->name()
-                  << ": " << error << std::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;
     }
   }
 
@@ -1319,6 +1546,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());
   }
@@ -1451,13 +1679,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);
       }
@@ -1492,7 +1726,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) {
@@ -1502,13 +1738,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);
   }
@@ -1563,6 +1804,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) {
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 74a0adb..f196ffc 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();
@@ -247,6 +249,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 +262,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 +364,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 3d27829..dda007d 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -63,13 +63,13 @@
 #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
-namespace google {
-namespace protobuf {
-namespace compiler {
 
 #if defined(_WIN32)
 #ifndef STDIN_FILENO
@@ -115,6 +115,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);
   }
@@ -179,6 +189,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_;
@@ -280,6 +293,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.
@@ -297,17 +315,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 {
@@ -459,6 +480,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) {
@@ -854,6 +886,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) {
@@ -943,6 +1016,80 @@
   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) {
@@ -1274,6 +1421,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.
 
@@ -1663,8 +1822,8 @@
 
 }  // anonymous namespace
 
+#endif  // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+
 }  // namespace compiler
 }  // namespace protobuf
-
-#endif  // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
 }  // 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 08fec77..47729e1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -133,8 +133,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 0404b73..1a11bce 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>
@@ -70,19 +69,27 @@
 
 EnumGenerator::~EnumGenerator() {}
 
+void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) {
+  if (!options_.proto_h) {
+    return;
+  }
+  enum_names->insert(classname_);
+}
+
 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->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.
@@ -113,8 +120,8 @@
   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"] = "";
@@ -174,7 +181,7 @@
   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));
     printer->Print(vars,
       "static const $nested_name$ $tag$ = $classname$_$tag$;\n");
   }
@@ -271,14 +278,14 @@
   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");
     }
@@ -290,7 +297,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..f3aa72e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -35,6 +35,7 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 
+#include <set>
 #include <string>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.h>
@@ -60,6 +61,12 @@
 
   // 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.
+  void FillForwardDeclaration(set<string>* 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.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 7498970..824e220 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -35,7 +35,6 @@
 #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>
 
 namespace google {
@@ -242,7 +241,7 @@
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField<int> $name$_;\n");
-  if (descriptor_->options().packed()
+  if (descriptor_->is_packed()
       && HasGeneratedMethods(descriptor_->file())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
@@ -352,7 +351,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
-  if (!descriptor_->options().packed()) {
+  if (!descriptor_->is_packed()) {
       // This path is rarely executed, so we use a non-inlined implementation.
     if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
       printer->Print(variables_,
@@ -419,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"
@@ -432,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");
@@ -446,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"
@@ -460,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");
@@ -484,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_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_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 43df1d8..8d47d4e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -47,6 +47,7 @@
 #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>
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index cd2b6b7..1d7f823 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -82,12 +82,38 @@
   // implementation is empty.
   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, bool is_inline) const = 0;
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index a98c7d9..37e4bae 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -33,6 +33,7 @@
 //  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>
@@ -93,114 +94,91 @@
 
 FileGenerator::~FileGenerator() {}
 
-void FileGenerator::GenerateHeader(io::Printer* printer) {
+void FileGenerator::GenerateProtoHeader(io::Printer* printer) {
+  if (!options_.proto_h) {
+    return;
+  }
+
   string filename_identifier = FilenameIdentifier(file_->name());
+  GenerateTopHeaderGuard(printer, 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"
-    "\n",
-    "filename", file_->name(),
-    "filename_identifier", filename_identifier);
 
+  GenerateLibraryIncludes(printer);
+
+  for (int i = 0; i < file_->public_dependency_count(); i++) {
+    const FileDescriptor* dep = file_->public_dependency(i);
+    const char* extension = ".proto.h";
+    string dependency = StripProto(dep->name()) + extension;
+    printer->Print(
+      "#include \"$dependency$\"  // IWYU pragma: export\n",
+      "dependency", dependency);
+  }
 
   printer->Print(
-    "#include <google/protobuf/stubs/common.h>\n"
+    "// @@protoc_insertion_point(includes)\n");
+
+
+  GenerateForwardDeclarations(printer);
+
+  // Open namespace.
+  GenerateNamespaceOpeners(printer);
+
+  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"
+    "// @@protoc_insertion_point(namespace_scope)\n"
     "\n");
 
-  // Verify the protobuf library header version is compatible with the protoc
-  // version before going any further.
+  // Close up namespace.
+  GenerateNamespaceClosers(printer);
+
+  // We need to specialize some templates in the ::google::protobuf namespace:
+  GenerateProto2NamespaceEnumSpecializations(printer);
+
   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));
+    "\n"
+    "// @@protoc_insertion_point(global_scope)\n"
+    "\n");
 
-  // 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_)) {
-    printer->Print(
-      "#include <google/protobuf/metadata.h>\n");
+  GenerateBottomHeaderGuard(printer, filename_identifier);
+}
+
+void FileGenerator::GeneratePBHeader(io::Printer* printer) {
+  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);
   }
-  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 (HasMapFields(file_)) {
-    printer->Print(
-        "#include <google/protobuf/map.h>\n");
-    if (HasDescriptorMethods(file_)) {
-      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_)) {
-      printer->Print(
-          "#include <google/protobuf/generated_enum_reflection.h>\n");
-    } else {
-      printer->Print(
-          "#include <google/protobuf/generated_enum_util.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);
-
-
-    printer->Print(
-      "#include \"$dependency$.pb.h\"$iwyu$\n",
-      "dependency", StripProto(name),
-      "iwyu", (public_import) ? "  // IWYU pragma: export" : "");
-  }
+  GenerateDependencyIncludes(printer);
 
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
@@ -210,93 +188,33 @@
   // Open namespace.
   GenerateNamespaceOpeners(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 + " ");
+  if (!options_.proto_h) {
+    GenerateGlobalStateFunctionDeclarations(printer);
+    GenerateMessageForwardDeclarations(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()));
+    printer->Print("\n");
 
-  // Generate forward declarations of classes.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateForwardDeclaration(printer);
-  }
+    GenerateEnumDefinitions(printer);
 
-  printer->Print("\n");
+    printer->Print(kThickSeparator);
+    printer->Print("\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);
-  }
-
-  printer->Print("\n");
-  printer->Print(kThickSeparator);
-  printer->Print("\n");
-
-  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);
-    }
+    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("#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("\n");
+    printer->Print(kThickSeparator);
+    printer->Print("\n");
+
+    GenerateInlineFunctionDefinitions(printer);
   }
-  printer->Print("#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
 
   printer->Print(
     "\n"
@@ -305,27 +223,9 @@
   // Close up namespace.
   GenerateNamespaceClosers(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");
+  if (!options_.proto_h) {
+    // We need to specialize some templates in the ::google::protobuf namespace:
+    GenerateProto2NamespaceEnumSpecializations(printer);
   }
 
   printer->Print(
@@ -333,30 +233,33 @@
     "// @@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) {
+  bool well_known = 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", well_known ? "<" : "\"",
+    "right", well_known ? ">" : "\"");
 
   // Unknown fields implementation in lite mode uses StringOutputStream
   if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
@@ -372,6 +275,18 @@
       "#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");
 
@@ -467,6 +382,59 @@
     "// @@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;
+  }
+
+  set<string>& classes() { return classes_; }
+  set<string>& enums() { return enums_; }
+
+  void Print(io::Printer* printer) const {
+    for (set<string>::const_iterator it = enums_.begin(), end = enums_.end();
+         it != end; ++it) {
+      printer->Print("enum $enumname$ : int;\n"
+                     "bool $enumname$_IsValid(int value);\n",
+                     "enumname", it->c_str());
+    }
+    for (set<string>::const_iterator it = classes_.begin(),
+                                     end = classes_.end();
+         it != end; ++it) {
+      printer->Print("class $classname$;\n", "classname", it->c_str());
+    }
+    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_;
+  set<string> classes_;
+  set<string> 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
@@ -625,20 +593,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(
@@ -707,6 +715,328 @@
   }
 }
 
+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"
+    "\n",
+    "filename", file_->name(),
+    "filename_identifier", filename_identifier);
+}
+
+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_)) {
+    printer->Print(
+      "#include <google/protobuf/metadata.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 (HasMapFields(file_)) {
+    printer->Print(
+        "#include <google/protobuf/map.h>\n");
+    if (HasDescriptorMethods(file_)) {
+      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_)) {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_reflection.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_util.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");
+  }
+
+
+  if (IsAnyMessage(file_)) {
+    printer->Print(
+      "#include <google/protobuf/any.h>\n");
+  }
+}
+
+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++) {
+    bool well_known = 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", well_known ? "<" : "\"",
+      "right", well_known ? ">" : "\"");
+  }
+}
+
+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) {
+  set<string> classes;
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->FillMessageForwardDeclarations(&classes);
+  }
+  for (set<string>::const_iterator it = classes.begin(), end = classes.end();
+       it != end; ++it) {
+    printer->Print("class $classname$;\n", "classname", it->c_str());
+  }
+}
+
+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_)) {
+    // 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 0e06547..29cdaea 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -69,10 +69,14 @@
                          const Options& options);
   ~FileGenerator();
 
-  void GenerateHeader(io::Printer* printer);
+  void GenerateProtoHeader(io::Printer* printer);
+  void GeneratePBHeader(io::Printer* printer);
   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);
@@ -80,6 +84,55 @@
   void GenerateNamespaceOpeners(io::Printer* printer);
   void GenerateNamespaceClosers(io::Printer* printer);
 
+  // For other imports, generates their forward-declarations.
+  void GenerateForwardDeclarations(io::Printer* printer);
+
+  // 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);
+
+  // 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_;
 
   google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index c999b93..781526b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -82,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++) {
@@ -99,16 +100,23 @@
 
 
   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"));
+    io::Printer printer(output.get(), '$');
+    file_generator.GenerateProtoHeader(&printer);
+  }
+
+  basename.append(".pb");
   {
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         generator_context->Open(basename + ".h"));
     io::Printer printer(output.get(), '$');
-    file_generator.GenerateHeader(&printer);
+    file_generator.GeneratePBHeader(&printer);
   }
 
   // Generate cc file.
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 237278d..fb46e38 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);
 }
@@ -65,7 +70,7 @@
   "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
   "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
   "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
-  "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or",
+  "namespace", "new", "noexcept", "not", "not_eq", "NULL", "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",
@@ -162,11 +167,23 @@
 }
 
 
+string DependentBaseClassTemplateName(const Descriptor* descriptor) {
+  return ClassName(descriptor, false) + "_InternalBase";
+}
+
 string SuperClassName(const Descriptor* descriptor) {
   return HasDescriptorMethods(descriptor->file()) ?
       "::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) {
   string result = field->name();
   LowerString(&result);
@@ -176,6 +193,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";
@@ -192,6 +217,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.
@@ -352,7 +431,7 @@
     } else {
       // Not alphanumeric.  To avoid any possibility of name conflicts we
       // use the hex code for the character.
-      StrAppend(&result, "_", ToHex(static_cast<uint8>(filename[i])));
+      StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
     }
   }
   return result;
@@ -513,6 +592,107 @@
 
 }
 
+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) {
+  if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    return STRICT;
+  } else if (field->file()->options().optimize_for() !=
+             FileOptions::LITE_RUNTIME) {
+    return VERIFY;
+  } else {
+    return NONE;
+  }
+}
+
+static void GenerateUtf8CheckCode(const FieldDescriptor* field,
+                                  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)) {
+    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,
+                                    bool for_parse,
+                                    const map<string, string>& variables,
+                                    const char* parameters,
+                                    io::Printer* printer) {
+  GenerateUtf8CheckCode(field, for_parse, variables, parameters,
+                        "VerifyUtf8String", "VerifyUTF8StringNamedField",
+                        printer);
+}
+
+void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
+                                  bool for_parse,
+                                  const map<string, string>& variables,
+                                  const char* parameters,
+                                  io::Printer* printer) {
+  GenerateUtf8CheckCode(field, 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 c7bb8f9..a22d414 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -66,14 +66,28 @@
 string ClassName(const Descriptor* descriptor, bool qualified);
 string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
 
+// 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);
 
+// 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
 // should be using lowercase-with-underscores style for proto field names
 // 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,6 +99,20 @@
     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);
@@ -174,11 +202,6 @@
          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.
@@ -239,6 +262,25 @@
   return SupportsArenas(field->file());
 }
 
+bool IsAnyMessage(const FileDescriptor* descriptor);
+bool IsAnyMessage(const Descriptor* descriptor);
+
+bool IsWellKnownMessage(const FileDescriptor* descriptor);
+
+void GenerateUtf8CheckCodeForString(
+    const FieldDescriptor* field,
+    bool for_parse,
+    const map<string, string>& variables,
+    const char* parameters,
+    io::Printer* printer);
+
+void GenerateUtf8CheckCodeForCord(
+    const FieldDescriptor* field,
+    bool for_parse,
+    const map<string, string>& variables,
+    const char* parameters,
+    io::Printer* printer);
+
 }  // 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
index 8c38db2..e5e2f07 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -66,7 +66,7 @@
       (*variables)["wrapper"] = "EntryWrapper";
       break;
     case FieldDescriptor::CPPTYPE_ENUM:
-      (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
+      (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
       (*variables)["wrapper"] = "EnumEntryWrapper";
       break;
     default:
@@ -100,8 +100,9 @@
 
 MapFieldGenerator::
 MapFieldGenerator(const FieldDescriptor* descriptor,
-                              const Options& options)
-    : descriptor_(descriptor) {
+                  const Options& options)
+    : descriptor_(descriptor),
+      dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
   SetMessageVariables(descriptor, &variables_, options);
 }
 
@@ -152,7 +153,9 @@
 
 void MapFieldGenerator::
 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 MapFieldGenerator::
@@ -197,7 +200,7 @@
       case FieldDescriptor::CPPTYPE_ENUM:
         printer->Print(variables_,
             "(*mutable_$name$())[entry->key()] =\n"
-            "    static_cast<$val_cpp$>(*entry->mutable_value());\n");
+            "    static_cast< $val_cpp$ >(*entry->mutable_value());\n");
         break;
       default:
         printer->Print(variables_,
@@ -212,7 +215,7 @@
         "  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"
+        "        static_cast< $val_cpp$ >(*entry->mutable_value());\n"
         "  } else {\n");
     if (HasDescriptorMethods(descriptor_->file())) {
       printer->Print(variables_,
@@ -231,6 +234,20 @@
         "}\n");
   }
 
+  const FieldDescriptor* key_field =
+      descriptor_->message_type()->FindFieldByName("key");
+  if (key_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        key_field, true, variables_,
+        "entry->key().data(), entry->key().length(),\n", printer);
+  }
+  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        value_field, 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_,
@@ -244,7 +261,8 @@
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\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_)) {
@@ -257,7 +275,30 @@
   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"
+      "        $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, false, variables_,
+        "it->first.data(), it->first.length(),\n", printer);
+  }
+  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        value_field, 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.
@@ -277,7 +318,8 @@
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\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_)) {
@@ -291,7 +333,29 @@
       "    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"
+      "            $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, false, variables_,
+        "it->first.data(), it->first.length(),\n", printer);
+  }
+  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        value_field, 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.
@@ -312,7 +376,8 @@
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\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_)) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
index d27d485..5e20562 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -63,6 +63,7 @@
 
  private:
   const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
   map<string, string> variables_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index bafa36f..8304ebb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -39,7 +39,6 @@
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
-#include <set>
 #include <utility>
 #include <vector>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
@@ -64,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')));
 }
@@ -280,6 +284,10 @@
   }
 }
 
+string MessageTypeProtoName(const FieldDescriptor* field) {
+  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
@@ -342,7 +350,7 @@
       (*variables)["val"] = FieldMessageTypeName(val);
       break;
     case FieldDescriptor::CPPTYPE_ENUM:
-      (*variables)["val"] = ClassName(val->enum_type(), false);
+      (*variables)["val"] = ClassName(val->enum_type(), true);
       break;
     default:
       (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
@@ -379,7 +387,8 @@
       enum_generators_(
           new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
       extension_generators_(new google::protobuf::scoped_ptr<
-          ExtensionGenerator>[descriptor->extension_count()]) {
+          ExtensionGenerator>[descriptor->extension_count()]),
+      use_dependent_base_(false) {
 
   for (int i = 0; i < descriptor->nested_type_count(); i++) {
     nested_generators_[i].reset(
@@ -401,22 +410,38 @@
     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(set<string>* class_names) {
+  class_names->insert(classname_);
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // 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]->GenerateForwardDeclaration(printer);
+    nested_generators_[i]->FillMessageForwardDeclarations(class_names);
+  }
+}
+
+void MessageGenerator::
+FillEnumForwardDeclarations(set<string>* 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);
   }
 }
 
@@ -442,6 +467,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, "void clear_$name$()$deprecation$;\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);
@@ -452,6 +499,21 @@
     SetCommonFieldVariables(field, &vars, options_);
     vars["constant_name"] = FieldConstantName(field);
 
+    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));
+    }
+
     if (field->is_repeated()) {
       printer->Print(vars, "int $name$_size() const$deprecation$;\n");
     } else if (HasHasMethod(field)) {
@@ -463,7 +525,11 @@
           "public:\n");
     }
 
-    printer->Print(vars, "void clear_$name$()$deprecation$;\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, "void clear_$name$()$deprecation$;\n");
+    }
     printer->Print(vars, "static const int $constant_name$ = $number$;\n");
 
     // Generate type-specific accessor declarations.
@@ -490,6 +556,190 @@
 }
 
 void MessageGenerator::
+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_);
 
@@ -500,101 +750,45 @@
 
     map<string, string> vars;
     SetCommonFieldVariables(field, &vars, options_);
-    vars["inline"] = is_inline ? "inline" : "";
+    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
-      // 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).
       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");
-      printer->Print(vars,
-        "$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.
-      if (HasFieldPresence(descriptor_->file())) {
-        // N.B.: without field presence, we do not use has-bits or generate
-        // has_$name$() methods.
-        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"
-          );
-      } 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");
-          }
-        }
+      if (!use_dependent_base_ || !IsFieldDependent(field)) {
+        GenerateSingularFieldHasBits(field, vars, printer);
       }
     }
 
-    // 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 (HasFieldPresence(descriptor_->file())) {
-        if (!field->is_repeated()) {
-          printer->Print(vars,
-                         "clear_has_$name$();\n");
-        }
-      }
+    if (!use_dependent_base_ || !IsFieldDependent(field)) {
+      GenerateFieldClear(field, vars, printer);
     }
 
-    printer->Outdent();
-    printer->Print("}\n");
-
     // Generate type-specific accessors.
     field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
                                                                    is_inline);
@@ -602,23 +796,11 @@
     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_;
-    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");
+  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);
   }
 }
 
@@ -648,6 +830,34 @@
 }
 
 void MessageGenerator::
+GenerateDependentBaseClassDefinition(io::Printer* printer) {
+  if (!use_dependent_base_) {
+    return;
+  }
+
+  map<string, string> vars;
+  vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+  vars["superclass"] = SuperClassName(descriptor_);
+
+  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
@@ -660,6 +870,11 @@
     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());
@@ -669,11 +884,18 @@
   } else {
     vars["dllexport"] = options_.dllexport_decl + " ";
   }
-  vars["superclass"] = SuperClassName(descriptor_);
-
+  if (use_dependent_base_) {
+    vars["superclass"] =
+        DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
+  } else {
+    vars["superclass"] = SuperClassName(descriptor_);
+  }
   printer->Print(vars,
-    "class $dllexport$$classname$ : public $superclass$ {\n"
-    " public:\n");
+    "class $dllexport$$classname$ : public $superclass$ {\n");
+  if (use_dependent_base_) {
+    printer->Print(vars, "  friend class $superclass$;\n");
+  }
+  printer->Print(" public:\n");
   printer->Indent();
 
   printer->Print(vars,
@@ -700,15 +922,32 @@
         "}\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");
+      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");
+      }
     }
   }
 
@@ -782,6 +1021,19 @@
     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"
+      "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"
@@ -840,6 +1092,10 @@
     }
   }
   uses_string_ = false;
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file())) {
+    uses_string_ = true;
+  }
   for (int i = 0; i < descriptors.size(); i++) {
     const FieldDescriptor* field = descriptors[i];
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
@@ -1027,7 +1283,7 @@
       "::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");
   }
@@ -1139,6 +1395,12 @@
       "\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_.
@@ -1172,6 +1434,21 @@
 }
 
 void MessageGenerator::
+GenerateDependentInlineMethods(io::Printer* printer) {
+  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]->GenerateDependentInlineMethods(printer);
+    printer->Print(kThinSeparator);
+    printer->Print("\n");
+  }
+
+  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
@@ -1196,7 +1473,8 @@
     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"
@@ -1494,6 +1772,30 @@
 
 void MessageGenerator::
 GenerateClassMethods(io::Printer* printer) {
+  // mutable_unknown_fields wrapper function for LazyStringOutputStream
+  // callback.
+  if (!UseUnknownFieldSet(descriptor_->file())) {
+    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"
+      "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);
   }
@@ -1516,7 +1818,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(
@@ -1525,7 +1827,7 @@
       "constant_name", FieldConstantName(field));
   }
   printer->Print(
-    "#endif  // !_MSC_VER\n"
+    "#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n"
     "\n");
 
   // Define extension identifiers.
@@ -1649,6 +1951,13 @@
       uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "",
       "_cached_size_ = 0;\n").c_str());
 
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file())) {
+    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))
@@ -1685,6 +1994,22 @@
       "}\n"
       "\n");
   }
+
+  // Write the desctructor for _unknown_fields_ in lite runtime.
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file())) {
+    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()) {
@@ -1767,7 +2092,7 @@
   if (need_registration) {
     printer->Print(
         "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
-        "  if (arena != NULL) {"
+        "  if (arena != NULL) {\n"
         "    arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
         "  }\n"
         "}\n",
@@ -1782,18 +2107,23 @@
 
 void MessageGenerator::
 GenerateStructors(io::Printer* printer) {
-  string superclass = SuperClassName(descriptor_);
-  string initializer_with_arena;
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    initializer_with_arena = "_internal_metadata_(arena)";
+  string superclass;
+  if (use_dependent_base_) {
+    superclass =
+        DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
   } else {
-    initializer_with_arena = "_arena_ptr_(arena)";
+    superclass = SuperClassName(descriptor_);
   }
+  string initializer_with_arena = superclass + "()";
+
   if (descriptor_->extension_range_count() > 0) {
-      initializer_with_arena  = string("\n  _extensions_(arena)") +
-        (!initializer_with_arena.empty() ?  ", " : "") + initializer_with_arena;
+    initializer_with_arena += ",\n  _extensions_(arena)";
+  }
+
+  if (UseUnknownFieldSet(descriptor_->file())) {
+    initializer_with_arena += ",\n  _internal_metadata_(arena)";
   } else {
-    initializer_with_arena  = "\n  " + initializer_with_arena;
+    initializer_with_arena += ",\n  _arena_ptr_(arena)";
   }
 
   // Initialize member variables with arena constructor.
@@ -1804,16 +2134,21 @@
           FieldName(descriptor_->field(i)) + string("_(arena)");
     }
   }
-  initializer_with_arena = superclass + "()" +
-      (!initializer_with_arena.empty() ?  "," : " ") + initializer_with_arena;
+
+  if (IsAnyMessage(descriptor_)) {
+    initializer_with_arena += ",\n  _any_metadata_(&type_url, &value_)";
+  }
 
   string initializer_null;
   initializer_null = (UseUnknownFieldSet(descriptor_->file()) ?
-    ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)");
+    ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)");
+  if (IsAnyMessage(descriptor_)) {
+    initializer_null += ", _any_metadata_(&type_url_, &value_)";
+  }
 
   printer->Print(
       "$classname$::$classname$()\n"
-      "  : $superclass$() $initializer$ {\n"
+      "  : $superclass$()$initializer$ {\n"
       "  SharedCtor();\n"
       "  // @@protoc_insertion_point(constructor:$full_name$)\n"
       "}\n",
@@ -1894,10 +2229,14 @@
     "full_name", descriptor_->full_name());
   if (UseUnknownFieldSet(descriptor_->file())) {
     printer->Print(
-        ",\n    _internal_metadata_(NULL) {\n");
+        ",\n    _internal_metadata_(NULL)");
   } else if (!UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print(",\n    _arena_ptr_(NULL) {\n");
+    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"
@@ -2096,7 +2435,7 @@
       } else {
         if (HasFieldPresence(descriptor_->file())) {
           printer->Print(
-            "if (_has_bits_[$index$ / 32] & $mask$) {\n",
+            "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
             "index", SimpleItoa(i / 8 * 8),
             "mask", SimpleItoa(mask));
           printer->Indent();
@@ -2124,7 +2463,11 @@
       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 (have_enclosing_if) {
       printer->Outdent();
@@ -2147,7 +2490,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);
+      }
     }
   }
 
@@ -2171,8 +2518,16 @@
         "  mutable_unknown_fields()->Clear();\n"
         "}\n");
     } else {
-      printer->Print(
-        "mutable_unknown_fields()->clear();\n");
+      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");
+      }
     }
   }
 
@@ -2184,14 +2539,16 @@
 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();
+    string message_class;
+
+    printer->Print(oneof_vars,
+        "void $classname$::clear_$oneofname$() {\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);
@@ -2297,7 +2654,7 @@
         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");
       }
     } else {
       // Still swap internal_metadata as it may contain more than just
@@ -2333,9 +2690,9 @@
     // 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"
       "  ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
       "} else {\n"
@@ -2468,7 +2825,9 @@
         "}\n");
     } else {
       printer->Print(
-        "mutable_unknown_fields()->append(from.unknown_fields());\n");
+        "if (!from.unknown_fields().empty()) {\n"
+        "  mutable_unknown_fields()->append(from.unknown_fields());\n"
+        "}\n");
     }
   }
 
@@ -2543,11 +2902,16 @@
     "classname", classname_);
 
   if (!UseUnknownFieldSet(descriptor_->file())) {
+    // 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(
@@ -2585,8 +2949,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);
 
@@ -2600,14 +2980,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);
@@ -2615,7 +3002,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",
@@ -2625,7 +3012,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",
@@ -2644,26 +3031,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(
@@ -2968,7 +3382,7 @@
     } else {
       printer->Print(
         "output->WriteRaw(unknown_fields().data(),\n"
-        "                 unknown_fields().size());\n");
+        "                 static_cast<int>(unknown_fields().size()));\n");
     }
   }
 }
@@ -2999,9 +3413,7 @@
   vector<string> parts;
   for (int i = 0; i < masks.size(); i++) {
     if (masks[i] == 0) continue;
-    char buffer[kFastToBufferSize];
-    FastHex32ToBuffer(masks[i], buffer);
-    string m = StrCat("0x", buffer);
+    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, ")"));
   }
@@ -3147,7 +3559,7 @@
         } else {
           if (HasFieldPresence(descriptor_->file())) {
             printer->Print(
-              "if (_has_bits_[$index$ / 32] & $mask$) {\n",
+              "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
               "index", SimpleItoa(i),
               "mask", SimpleItoa(mask));
             printer->Indent();
@@ -3293,11 +3705,10 @@
       }
 
       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));
+          "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8)));
       }
     }
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index ea96581..8e19a3f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -39,8 +39,8 @@
 #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>
 
@@ -66,8 +66,10 @@
 
   // 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.
+  void FillMessageForwardDeclarations(set<string>* class_names);
+  void FillEnumForwardDeclarations(set<string>* enum_names);
 
   // Generate definitions of all nested enums (must come before class
   // definitions because those classes use the enums definitions).
@@ -84,6 +86,9 @@
   // file).
   void GenerateInlineMethods(io::Printer* printer, bool is_inline);
 
+  // Dependent methods are always inline.
+  void GenerateDependentInlineMethods(io::Printer* printer);
+
   // Source file stuff.
 
   // Generate code which declares all the global descriptor pointers which
@@ -115,7 +120,10 @@
 
  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 GenerateDependentFieldAccessorDefinitions(io::Printer* printer);
   void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
 
   // Generate the field offsets array.
@@ -158,6 +166,21 @@
       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_;
@@ -168,6 +191,7 @@
   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 467b6bf..b454589 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -63,6 +63,14 @@
       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
@@ -72,7 +80,8 @@
 MessageFieldGenerator::
 MessageFieldGenerator(const FieldDescriptor* descriptor,
                       const Options& options)
-  : descriptor_(descriptor) {
+  : descriptor_(descriptor),
+    dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
   SetMessageVariables(descriptor, &variables_, options);
 }
 
@@ -84,6 +93,24 @@
 }
 
 void MessageFieldGenerator::
+GenerateGetterDeclaration(io::Printer* printer) const {
+  printer->Print(variables_,
+      "const $type$& $name$() const$deprecation$;\n");
+}
+
+void MessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+  if (!dependent_field_) {
+    return;
+  }
+  // Arena manipulation code is out-of-line in the derived message class.
+  printer->Print(variables_,
+    "$type$* mutable_$name$()$deprecation$;\n"
+    "$type$* $release_name$()$deprecation$;\n"
+    "void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+}
+
+void MessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
@@ -98,11 +125,13 @@
        "$type$* _slow_$release_name$()$deprecation$;\n"
        "public:\n");
   }
-  printer->Print(variables_,
-    "const $type$& $name$() const$deprecation$;\n"
-    "$type$* mutable_$name$()$deprecation$;\n"
-    "$type$* $release_name$()$deprecation$;\n"
-    "void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+  GenerateGetterDeclaration(printer);
+  if (!dependent_field_) {
+    printer->Print(variables_,
+      "$type$* mutable_$name$()$deprecation$;\n"
+      "$type$* $release_name$()$deprecation$;\n"
+      "void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+  }
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
       "$type$* unsafe_arena_release_$name$()$deprecation$;\n"
@@ -118,12 +147,12 @@
       "void $classname$::_slow_mutable_$name$() {\n");
       if (SupportsArenas(descriptor_->message_type())) {
         printer->Print(variables_,
-        "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-      "        GetArenaNoVirtual());\n");
+          "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+          "      GetArenaNoVirtual());\n");
       } else {
         printer->Print(variables_,
-         "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
-         "     GetArenaNoVirtual());\n");
+          "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
+          "      GetArenaNoVirtual());\n");
       }
     printer->Print(variables_,
       "}\n"
@@ -144,7 +173,9 @@
       "  return temp;\n"
       "}\n");
     if (SupportsArenas(descriptor_->message_type())) {
-        printer->Print(variables_,
+      // 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"
@@ -181,12 +212,140 @@
 }
 
 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"
+      "  $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"
+      "  $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" : "";
+  variables["inline"] = is_inline ? "inline " : "";
   printer->Print(variables,
-    "$inline$ const $type$& $classname$::$name$() const {\n"
+    "$inline$const $type$& $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n");
 
   PrintHandlingOptionalStaticInitializers(
@@ -195,19 +354,25 @@
     "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
     // Without.
     "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
+  printer->Print(variables, "}\n");
+
+  if (dependent_field_) {
+    return;
+  }
 
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables,
-      "}\n"
-      "$inline$ $type$* $classname$::mutable_$name$() {\n"
+      "$inline$"
+      "$type$* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  if ($name$_ == NULL) {\n"
-      "    _slow_mutable_$name$();"
+      "    _slow_mutable_$name$();\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_;\n"
       "}\n"
-      "$inline$ $type$* $classname$::$release_name$() {\n"
+      "$inline$"
+      "$type$* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  if (GetArenaNoVirtual() != NULL) {\n"
       "    return _slow_$release_name$();\n"
@@ -217,7 +382,8 @@
       "    return temp;\n"
       "  }\n"
       "}\n"
-      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\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"
@@ -249,8 +415,8 @@
       "}\n");
   } else {
     printer->Print(variables,
-      "}\n"
-      "$inline$ $type$* $classname$::mutable_$name$() {\n"
+      "$inline$"
+      "$type$* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  if ($name$_ == NULL) {\n"
       "    $name$_ = new $type$;\n"
@@ -258,13 +424,15 @@
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_;\n"
       "}\n"
-      "$inline$ $type$* $classname$::$release_name$() {\n"
+      "$inline$"
+      "$type$* $classname$::$release_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"
+      "$inline$"
+      "void $classname$::set_allocated_$name$($type$* $name$) {\n"
       "  delete $name$_;\n");
 
     if (SupportsArenas(descriptor_->message_type())) {
@@ -290,15 +458,19 @@
 
 void MessageFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
+  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 ($name$_ != NULL) delete $name$_;\n"
-      "$name$_ = NULL;\n");
+    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 ($name$_ != NULL) $name$_->$type$::Clear();\n");
+    printer->Print(variables,
+      "if ($this_message$$name$_ != NULL) $this_message$$name$_->"
+      "$dependent_type$::Clear();\n");
   }
 }
 
@@ -359,63 +531,180 @@
 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::
+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_,
+      "const $type$& $name$() const$deprecation$;\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_,
+      "const $type$& $name$() const$deprecation$;\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["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,
-      "$inline$ const $type$& $classname$::$name$() const {\n"
-      "  // @@protoc_insertion_point(field_get:$full_name$)\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");
+      "$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,
-         "    $oneof_prefix$$name$_ = \n"
-         "      ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-         "      GetArenaNoVirtual());\n");
+         "    $field_member$ = \n"
+         "      ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n"
+         "      $this_message$GetArenaNoVirtual());\n");
     } else {
       printer->Print(variables,
-         "    $oneof_prefix$$name$_ = \n"
-         "      ::google::protobuf::Arena::Create< $type$ >(\n"
-         "      GetArenaNoVirtual());\n");
+         "    $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 $oneof_prefix$$name$_;\n"
+      "  return $field_member$;\n"
       "}\n"
-      "$inline$ $type$* $classname$::$release_name$() {\n"
-      "  if (has_$name$()) {\n"
-      "    clear_has_$oneof_name$();\n"
-      "    if (GetArenaNoVirtual() != NULL) {\n"
+      "$tmpl$"
+      "$inline$"
+      "$type$* $dependent_classname$::$release_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).
-      "      $type$* temp = new $type$;\n"
-      "      temp->MergeFrom(*$oneof_prefix$$name$_);\n"
-      "      $oneof_prefix$$name$_ = NULL;\n"
+      "      $dependent_typename$* temp = new $dependent_typename$;\n"
+      "      temp->MergeFrom(*$field_member$);\n"
+      "      $field_member$ = NULL;\n"
       "      return temp;\n"
       "    } else {\n"
-      "      $type$* temp = $oneof_prefix$$name$_;\n"
-      "      $oneof_prefix$$name$_ = NULL;\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"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
@@ -426,41 +715,8 @@
       "    return NULL;\n"
       "  }\n"
       "}\n"
-      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
-      "  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 (GetArenaNoVirtual() != NULL &&\n"
-        "        ::google::protobuf::Arena::GetArena($name$) == NULL) {\n"
-        "      GetArenaNoVirtual()->Own($name$);\n"
-        "    } else if (GetArenaNoVirtual() !=\n"
-        "               ::google::protobuf::Arena::GetArena($name$)) {\n"
-        "      $type$* new_$name$ = \n"
-        "          ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-        "          GetArenaNoVirtual());\n"
-        "      new_$name$->CopyFrom(*$name$);\n"
-        "      $name$ = new_$name$;\n"
-        "    }\n");
-    } else {
-      printer->Print(variables,
-        "    if (GetArenaNoVirtual() != NULL) {\n"
-        "      GetArenaNoVirtual()->Own($name$);\n"
-        "    }\n");
-    }
-
-    printer->Print(variables,
-      "    set_has_$name$();\n"
-      "    $oneof_prefix$$name$_ = $name$;\n"
-      "  }\n"
-      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
-      "}\n"
-      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
-      "$type$* $name$) {\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.
@@ -474,44 +730,47 @@
       "}\n");
   } else {
     printer->Print(variables,
-      "$inline$ const $type$& $classname$::$name$() const {\n"
-      "  // @@protoc_insertion_point(field_get:$full_name$)\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"
+      "$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 $oneof_prefix$$name$_;\n"
+      "  return $field_member$;\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"
+      "$tmpl$"
+      "$inline$"
+      "$type$* $dependent_classname$::$release_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"
-      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
-      "  clear_$oneof_name$();\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 ($name$->GetArena() != NULL) {\n"
-        "      $type$* new_$name$ = new $type$;\n"
+        "    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,
-      "    set_has_$name$();\n"
-      "    $oneof_prefix$$name$_ = $name$;\n"
+      "    $this_message$set_has_$name$();\n"
+      "    $field_member$ = $name$;\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\n");
@@ -520,14 +779,16 @@
 
 void MessageOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-      "if (GetArenaNoVirtual() == NULL) {\n"
-      "  delete $oneof_prefix$$name$_;\n"
+    printer->Print(variables,
+      "if ($this_message$GetArenaNoVirtual() == NULL) {\n"
+      "  delete $this_message$$oneof_prefix$$name$_;\n"
       "}\n");
   } else {
-    printer->Print(variables_,
-      "delete $oneof_prefix$$name$_;\n");
+    printer->Print(variables,
+      "delete $this_message$$oneof_prefix$$name$_;\n");
   }
 }
 
@@ -547,7 +808,9 @@
 RepeatedMessageFieldGenerator::
 RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
                               const Options& options)
-  : descriptor_(descriptor) {
+  : descriptor_(descriptor),
+    dependent_field_(options.proto_h && IsFieldDependent(descriptor)),
+    dependent_getter_(dependent_field_ && options.safe_boundary_check) {
   SetMessageVariables(descriptor, &variables_, options);
 }
 
@@ -560,52 +823,160 @@
 }
 
 void RepeatedMessageFieldGenerator::
-GenerateAccessorDeclarations(io::Printer* printer) const {
+InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "const $type$& $name$(int index) const$deprecation$;\n"
     "$type$* mutable_$name$(int index)$deprecation$;\n"
     "$type$* add_$name$()$deprecation$;\n");
+  if (dependent_getter_) {
+    printer->Print(variables_,
+      "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+      "    $name$() const$deprecation$;\n");
+  }
   printer->Print(variables_,
-    "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-    "    $name$() const$deprecation$;\n"
     "::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "    mutable_$name$()$deprecation$;\n");
 }
 
 void RepeatedMessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+  if (dependent_getter_) {
+    printer->Print(variables_,
+      "const $type$& $name$(int index) const$deprecation$;\n");
+  }
+  if (dependent_field_) {
+    InternalGenerateTypeDependentAccessorDeclarations(printer);
+  }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+  if (!dependent_getter_) {
+    printer->Print(variables_,
+      "const $type$& $name$(int index) const$deprecation$;\n");
+  }
+  if (!dependent_field_) {
+    InternalGenerateTypeDependentAccessorDeclarations(printer);
+  }
+  if (!dependent_getter_) {
+    printer->Print(variables_,
+      "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+      "    $name$() const$deprecation$;\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 $this_message$$name$_.Mutable(index);\n"
+    "}\n"
+    "template <class T>\n"
+    "inline $type$* $dependent_classname$::add_$name$() {\n"
+    "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+    "  return $this_message$$name$_.Add();\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"
+    "$dependent_classname$::mutable_$name$() {\n"
+    "  // @@protoc_insertion_point(field_mutable_list:$full_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" : "";
-  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"
-    "  // @@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");
-  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"
-    "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n"
-    "$classname$::mutable_$name$() {\n"
-    "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
-    "  return &$name$_;\n"
-    "}\n");
+  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::
@@ -627,11 +998,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");
   }
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index c1704fc..35efd0f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -52,7 +52,9 @@
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(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;
@@ -66,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:
@@ -80,14 +88,23 @@
   ~MessageOneofFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 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);
 };
 
@@ -99,7 +116,9 @@
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(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;
@@ -112,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..4463f20 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -41,12 +41,13 @@
 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) {
   }
   string dllexport_decl;
   bool safe_boundary_check;
+  bool proto_h;
 };
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 329eae3..9f929d3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -262,7 +262,7 @@
   : descriptor_(descriptor) {
   SetPrimitiveVariables(descriptor, &variables_, options);
 
-  if (descriptor->options().packed()) {
+  if (descriptor->is_packed()) {
     variables_["packed_reader"] = "ReadPackedPrimitive";
     variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
   } else {
@@ -277,7 +277,7 @@
 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())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -364,7 +364,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"
@@ -377,7 +377,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");
@@ -391,7 +391,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"
@@ -405,7 +405,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");
@@ -435,7 +435,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_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 1a1bcd3..6b0821a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -226,7 +226,6 @@
       "  } else {\n"
       "    $clear_hasbit$\n"
       "  }\n"
-      "  $set_hasbit$\n"
       "  $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
       "      $name$, GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
@@ -368,25 +367,19 @@
     "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"
-      "  \"$full_name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, 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"
-      "  \"$full_name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, false, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
   }
   printer->Print(variables_,
     "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n"
@@ -395,13 +388,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"
-      "  \"$full_name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, false, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
   }
   printer->Print(variables_,
     "target =\n"
@@ -422,7 +412,8 @@
 StringOneofFieldGenerator::
 StringOneofFieldGenerator(const FieldDescriptor* descriptor,
                           const Options& options)
-  : StringFieldGenerator(descriptor, options) {
+    : StringFieldGenerator(descriptor, options),
+      dependent_field_(options.proto_h) {
   SetCommonOneofFieldVariables(descriptor, &variables_);
 }
 
@@ -605,13 +596,29 @@
 
 void StringOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-      "$oneof_prefix$$name$_.Destroy($default_variable$,\n"
-      "    GetArenaNoVirtual());\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 {
-    printer->Print(variables_,
-      "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n");
+    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");
   }
 }
 
@@ -649,13 +656,10 @@
       "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"
-      "  \"$full_name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, true, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
   }
 }
 
@@ -665,7 +669,7 @@
 RepeatedStringFieldGenerator::
 RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
                              const Options& options)
-  : descriptor_(descriptor) {
+    : descriptor_(descriptor) {
   SetStringVariables(descriptor, &variables_, options);
 }
 
@@ -801,14 +805,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"
-      "  \"$full_name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, true, variables_,
+        "this->$name$(this->$name$_size() - 1).data(),\n"
+        "this->$name$(this->$name$_size() - 1).length(),\n",
+        printer);
   }
 }
 
@@ -816,14 +818,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"
-      "  \"$full_name$\");\n");
+  printer->Indent();
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, 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"
@@ -834,14 +835,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"
-      "    \"$full_name$\");\n");
+  printer->Indent();
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, 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 d1f19cd..616e206 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -93,6 +93,7 @@
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
 
  private:
+  const bool dependent_field_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
 };
 
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 4fa3c14..4e25b2e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -131,6 +131,24 @@
   }                                                              // 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 {}
 
 service TestConflictingMethodNames {
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 2a04b29..9942a34 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -55,6 +55,11 @@
 #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>
@@ -66,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>
@@ -75,6 +82,7 @@
 
 namespace google {
 namespace protobuf {
+using internal::NewPermanentCallback;
 namespace compiler {
 namespace cpp {
 
@@ -130,6 +138,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
 
 // ===================================================================
@@ -794,6 +815,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) {
@@ -926,6 +962,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) {
@@ -1377,6 +1429,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;
@@ -1389,6 +1447,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;
     }
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..422eb73
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -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.
+
+#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/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+namespace {
+
+}  // 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..5668198
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -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.
+
+#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>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) :
+    SourceGeneratorBase(descriptor->file()),
+    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();
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+      WriteEnumValueDocComment(printer, descriptor_->value(i));
+      printer->Print("$name$ = $number$,\n",
+                   "name", descriptor_->value(i)->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..2cf2fad
--- /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);
+  ~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..d38fb1e
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
@@ -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.
+
+#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_enum_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       int fieldOrdinal)
+    : PrimitiveFieldGenerator(descriptor, fieldOrdinal) {
+}
+
+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)
+  : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal) {
+}
+
+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..0836415
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h
@@ -0,0 +1,77 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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);
+  ~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);
+  ~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..5df43d3
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -0,0 +1,425 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)
+    : SourceGeneratorBase(descriptor->file()),
+      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:
+      return type_name() + "." + descriptor->default_value_enum()->name();
+    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..d83543b
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.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_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);
+  ~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..825de54
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -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.
+
+#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_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) {
+  ReflectionClassGenerator reflectionClassGenerator(file);
+  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;
+  }
+
+  std::string file_extension = ".cs";
+  std::string base_namespace = "";
+  bool generate_directories = false;
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "file_extension") {
+      file_extension = options[i].second;
+    } else if (options[i].first == "base_namespace") {
+      base_namespace = options[i].second;
+      generate_directories = true;
+    } else {
+      *error = "Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  string filename_error = "";
+  std::string filename = GetOutputFile(file, file_extension, generate_directories, 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);
+
+  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..7ef7df4
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
@@ -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.
+
+#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 csharp {
+namespace {
+
+// TODO(jtattermusch): add some tests.
+
+}  // 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..c51fe44
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -0,0 +1,405 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_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);
+}
+
+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) {
+  switch (descriptor->type()) {
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      if (descriptor->is_repeated()) {
+        if (descriptor->is_map()) {
+          return new MapFieldGenerator(descriptor, fieldOrdinal);
+        } else {
+          return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal);
+        }
+      } else {
+        if (IsWrapperType(descriptor)) {
+          if (descriptor->containing_oneof()) {
+            return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal);
+          } else {
+            return new WrapperFieldGenerator(descriptor, fieldOrdinal);
+          }
+        } else {
+          if (descriptor->containing_oneof()) {
+            return new MessageOneofFieldGenerator(descriptor, fieldOrdinal);
+          } else {
+            return new MessageFieldGenerator(descriptor, fieldOrdinal);
+          }
+        }
+      }
+    case FieldDescriptor::TYPE_ENUM:
+      if (descriptor->is_repeated()) {
+        return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal);
+      } else {
+        if (descriptor->containing_oneof()) {
+          return new EnumOneofFieldGenerator(descriptor, fieldOrdinal);
+        } else {
+          return new EnumFieldGenerator(descriptor, fieldOrdinal);
+        }
+      }
+    default:
+      if (descriptor->is_repeated()) {
+        return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal);
+      } else {
+        if (descriptor->containing_oneof()) {
+          return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal);
+        } else {
+          return new PrimitiveFieldGenerator(descriptor, fieldOrdinal);
+        }
+      }
+  }
+}
+
+}  // 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..e96e793
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -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.
+
+// 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/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 {
+
+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);
+
+// 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);
+
+// 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..15c68b3
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -0,0 +1,138 @@
+// 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)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+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));  
+  scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
+
+  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..f33fe1c
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_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_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);
+  ~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..e0230a2
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -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.
+
+#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)
+    : SourceGeneratorBase(descriptor->file()),
+      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));
+      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));
+        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));
+}
+
+}  // 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..f0c49ac
--- /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);
+  ~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..f81f769
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.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 <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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             int fieldOrdinal)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+  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)
+    : MessageFieldGenerator(descriptor, fieldOrdinal) {
+  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..dc6e4dc
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.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_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);
+  ~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);
+  ~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_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
new file mode 100644
index 0000000..60afd89
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -0,0 +1,217 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+  // 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)
+    : PrimitiveFieldGenerator(descriptor, fieldOrdinal) {
+  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..8b87ebc
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
@@ -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.
+
+#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 {
+
+class PrimitiveFieldGenerator : public FieldGeneratorBase {
+ public:
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+  ~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);
+  ~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..22dae43
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
@@ -0,0 +1,291 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_reflection_class.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file)
+    : SourceGeneratorBase(file),
+      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));
+      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));
+      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..0a5b8ed
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.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_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);
+  ~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..3a11b75
--- /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)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+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..ee50eef
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_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_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);
+  ~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..fc12fae
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -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.
+
+#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)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+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_));
+    single_generator->GenerateCodecCode(printer);
+  } else {
+    scoped_ptr<FieldGeneratorBase> single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_));
+    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..cf601c7
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_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_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 {
+
+class RepeatedMessageFieldGenerator : public FieldGeneratorBase {
+ public:
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+  ~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..5fe0b20
--- /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)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+}
+
+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..f1ceeb5
--- /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);
+  ~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..735d164
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
@@ -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.
+
+#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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor)
+    : descriptor_(descriptor) {
+}
+
+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_) ? "internal" : "public";  // public_classes is always on.
+}
+
+}  // 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..6caef17
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.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_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 {
+
+class SourceGeneratorBase {
+ protected:
+  SourceGeneratorBase(const FileDescriptor* descriptor);
+  virtual ~SourceGeneratorBase();
+
+  std::string class_access_level();
+
+  void WriteGeneratedCodeAttributes(io::Printer* printer);
+
+ private:
+  const FileDescriptor* descriptor_;
+
+  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..6a3750e
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -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.
+
+#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_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
+                                       int fieldOrdinal)
+    : FieldGeneratorBase(descriptor, fieldOrdinal) {
+  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)
+    : WrapperFieldGenerator(descriptor, fieldOrdinal) {
+    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..6e2414a
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.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.
+
+#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 {
+
+class WrapperFieldGenerator : public FieldGeneratorBase {
+ public:
+  WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
+  ~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);
+  ~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 8333684..0d9093c 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -185,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,
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 43eb0ed..be19aa2 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -44,6 +44,7 @@
 #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/stubs/strutil.h>
@@ -70,6 +71,7 @@
   ~MockErrorCollector() {}
 
   string text_;
+  string warning_text_;
 
   // implements ErrorCollector ---------------------------------------
   void AddError(const string& filename, int line, int column,
@@ -77,6 +79,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);
+  }
 };
 
 // -------------------------------------------------------------------
@@ -122,6 +130,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_;
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 0353b60..5fc9b00 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -85,17 +85,10 @@
 
 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();
 
   for (int i = 0; i < canonical_values_.size(); i++) {
@@ -181,8 +174,8 @@
     "    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"
@@ -311,7 +304,6 @@
       "}\n"
       "\n");
 
-    // index is only used for reflection; lite implementation does not need it
     printer->Print("private final int index;\n");
   }
 
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 71a2ba4..558da96 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>
@@ -67,7 +68,13 @@
   (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
   (*variables)["default_number"] = SimpleItoa(
       descriptor->default_value_enum()->number());
-  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+  if (descriptor->is_packed()) {
+    (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag(
+        descriptor->number(),
+        internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+  } else {
+    (*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
@@ -641,7 +648,7 @@
       "}\n");
   }
 
-  if (descriptor_->options().packed() &&
+  if (descriptor_->is_packed() &&
       HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
@@ -884,7 +891,7 @@
 
 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"
@@ -915,7 +922,7 @@
     "}\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"
@@ -928,7 +935,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_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
new file mode 100644
index 0000000..e3e87c5
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -0,0 +1,966 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  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$.valueOf($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(int 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::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "if (other.has$capitalized_name$()) {\n"
+      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "}\n");
+  } else if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "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.";
+  }
+}
+
+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$.valueOf(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$.valueOf((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::
+GenerateMergingCode(io::Printer* printer) const {
+  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 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$.valueOf(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$.valueOf(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() &&
+      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$_ = newIntList($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::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations:
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\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
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "if (!$is_mutable$) {\n"
+      "  $name$_ = newIntList();\n"
+      "}\n"
+      "$name$_.addInt(rawValue);\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.valueOf(rawValue);\n"
+        "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  super.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  if (!$is_mutable$) {\n"
+      "    $name$_ = newIntList();\n"
+      "  }\n"
+      "  $name$_.addInt(rawValue);\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  // Wrap GenerateParsingCode's contents with a while loop.
+
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int oldLimit = input.pushLimit(length);\n"
+    "while(input.getBytesUntilLimit() > 0) {\n");
+  printer->Indent();
+
+  GenerateParsingCode(printer);
+
+  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..2c41c3e
--- /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 GenerateMergingCode(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 GenerateMergingCode(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 GenerateMergingCode(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..ed415ee
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -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.
+
+// 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"
+    "public static $classname$ valueOf(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$.valueOf(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..4db7085 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -181,8 +181,9 @@
   }
 }
 
-void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
+int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
     io::Printer* printer) {
+  int bytecode_estimate = 0;
   if (descriptor_->extension_scope() == NULL &&
       HasDescriptorMethods(descriptor_->file())) {
     // Only applies to non-nested, non-lite extensions.
@@ -190,15 +191,18 @@
         "$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..e69de29
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension_lite.cc
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..e69de29
--- /dev/null
+++ b/src/google/protobuf/compiler/java/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 af9978e..c543476 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -39,15 +39,22 @@
 #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>
@@ -133,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)) {
+            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)) {
+            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)) {
+            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:
@@ -153,6 +233,13 @@
   ReportUnexpectedPackedFieldsCall(printer);
 }
 
+ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {}
+
+void ImmutableFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  ReportUnexpectedPackedFieldsCall(printer);
+}
+
 // ===================================================================
 
 template <>
@@ -178,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 1cf360c..0e24da2 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -44,6 +44,7 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/logging.h>
 
 namespace google {
 namespace protobuf {
@@ -83,7 +84,6 @@
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
   virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
       const = 0;
-  virtual void GenerateStaticInitializationCode(io::Printer* printer) const {}
 
   virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
   virtual void GenerateHashCode(io::Printer* printer) const = 0;
@@ -94,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 GenerateMergingCode(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>
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index f1e3cf6..c817233 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -38,9 +38,11 @@
 #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>
@@ -62,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
@@ -69,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.
@@ -79,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()) {
@@ -106,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
@@ -139,6 +154,42 @@
   }
 }
 
+// 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 = 1<<15;  // aka 32K
+
+  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
 
@@ -231,8 +282,13 @@
 
   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_)) {
+        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);
@@ -270,9 +326,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();
@@ -303,12 +366,24 @@
   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
@@ -330,7 +405,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) {
@@ -339,10 +414,17 @@
     printer->Print(
       "com.google.protobuf.ExtensionRegistry registry =\n"
       "    com.google.protobuf.ExtensionRegistry.newInstance();\n");
-    for (int i = 0; i < extensions.size(); i++) {
+    FieldDescriptorSet::iterator it;
+    for (it = extensions.begin(); it != extensions.end(); it++) {
       google::protobuf::scoped_ptr<ExtensionGenerator> generator(
-          generator_factory_->NewExtensionGenerator(extensions[i]));
-      generator->GenerateRegistrationCode(printer);
+          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"
@@ -394,7 +476,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) {
@@ -467,13 +549,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_)) {
+        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_) {
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
index 2d1437f..92ef851 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.cc
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -38,6 +38,7 @@
 #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,7 +58,12 @@
 
 MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
     const Descriptor* descriptor) const {
-  return new ImmutableMessageGenerator(descriptor, context_);
+  if (descriptor->file()->options().optimize_for() ==
+      FileOptions::LITE_RUNTIME) {
+    return new ImmutableMessageLiteGenerator(descriptor, context_);
+  } else {
+    return new ImmutableMessageGenerator(descriptor, context_);
+  }
 }
 
 ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 62efbef..5392d6d 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -196,12 +196,6 @@
            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;
-}
-
 // Should we generate generic services for this file?
 inline bool HasGenericServices(const FileDescriptor *file) {
   return file->service_count() > 0 &&
@@ -316,6 +310,12 @@
   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.
@@ -330,10 +330,23 @@
   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 6e29a40..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");
 }
 
 
@@ -538,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".
@@ -723,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..283ba1d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -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.
+
+// 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::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  $name$_.merge(other.$name$_);\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.setByteString(input.readBytes(), 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::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!($has_oneof_case_message$)) {\n"
+    "  $oneof_name$_ = new $lazy_type$();\n"
+    "}\n"
+    "(($lazy_type$) $oneof_name$_).merge(\n"
+    "    ($lazy_type$) other.$oneof_name$_);\n"
+    "$set_oneof_case_message$;\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$_).setByteString(\n"
+    "    input.readBytes(), 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$_ = newProtobufList($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$_ = newProtobufList();\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..e85ec0f
--- /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 GenerateMergingCode(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 GenerateMergingCode(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
index cf1ef58..3e035c8 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -133,9 +133,11 @@
   (*variables)["set_mutable_bit_parser"] =
       GenerateSetBitMutableLocal(builderBitIndex);
 
+  (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+      "DefaultEntryHolder.defaultEntry";
   if (HasDescriptorMethods(descriptor->file())) {
     (*variables)["lite"] = "";
-    (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry";
+    (*variables)["map_field_parameter"] = (*variables)["default_entry"];
     (*variables)["descriptor"] =
         name_resolver->GetImmutableClassName(descriptor->file()) +
         ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
@@ -154,9 +156,7 @@
                                        int messageBitIndex,
                                        int builderBitIndex,
                                        Context* context)
-  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
-    builderBitIndex_(builderBitIndex), context_(context),
-    name_resolver_(context->GetNameResolver())  {
+  : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
   SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
                       context->GetFieldGeneratorInfo(descriptor),
                       name_resolver_, &variables_);
@@ -198,26 +198,20 @@
 }
 
 void ImmutableMapFieldGenerator::
-GenerateStaticInitializationCode(io::Printer* printer) const {
-  printer->Print(
-      variables_,
-      "$name$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");
-}
-
-void ImmutableMapFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(
       variables_,
-      "private static final com.google.protobuf.MapEntry$lite$<\n"
-      "    $type_parameters$> $name$DefaultEntry;\n");
+      "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"
@@ -291,7 +285,10 @@
       "  if ($name$_ == null) {\n"
       "    $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
       "        $map_field_parameter$);\n"
-      " }\n"
+      "  }\n"
+      "  if (!$name$_.isMutable()) {\n"
+      "    $name$_ = $name$_.copy();\n"
+      "  }\n"
       "  return $name$_;\n"
       "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
@@ -317,6 +314,14 @@
         "          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(
@@ -334,6 +339,14 @@
           "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_);
@@ -349,6 +362,14 @@
         "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");
   }
 }
 
@@ -381,10 +402,8 @@
 GenerateBuildingCode(io::Printer* printer) const {
   printer->Print(
       variables_,
-      // We do a copy of the map field to ensure that the built result is
-      // immutable. Implementation of this copy() method can do copy-on-write
-      // to defer this copy until further modifications are made on the field.
-      "result.$name$_ = internalGet$capitalized_name$().copy();\n");
+      "result.$name$_ = internalGet$capitalized_name$();\n"
+      "result.$name$_.makeImmutable();\n");
 }
 
 void ImmutableMapFieldGenerator::
@@ -402,7 +421,7 @@
         variables_,
         "com.google.protobuf.ByteString bytes = input.readBytes();\n"
         "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-        "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n");
+        "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
     printer->Print(
         variables_,
         "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
@@ -415,7 +434,7 @@
         variables_,
         "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
         "$name$ = input.readMessage(\n"
-        "    $name$DefaultEntry.getParserForType(), extensionRegistry);\n"
+        "    $default_entry$.getParserForType(), extensionRegistry);\n"
         "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
   }
 }
@@ -432,7 +451,7 @@
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-      "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setValue(entry.getValue())\n"
       "      .build();\n"
@@ -447,7 +466,7 @@
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-      "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setValue(entry.getValue())\n"
       "      .build();\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index 3e6dd97..f2768f3 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -60,7 +60,6 @@
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
-  void GenerateStaticInitializationCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCode(io::Printer* printer) const;
 
@@ -69,9 +68,6 @@
  private:
   const FieldDescriptor* descriptor_;
   map<string, string> variables_;
-  const int messageBitIndex_;
-  const int builderBitIndex_;
-  Context* context_;
   ClassNameResolver* name_resolver_;
 };
 
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..d203940
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -0,0 +1,483 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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,
+                         ClassNameResolver* name_resolver,
+                         map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*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"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  (*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),
+                      name_resolver_, &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::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "internalGetMutable$capitalized_name$().mergeFrom(\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$.valueOf($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..a09cd53
--- /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 GenerateMergingCode(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 e982a17..22a70c3 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -49,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>
@@ -93,43 +95,46 @@
   : MessageGenerator(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
+  GOOGLE_CHECK_NE(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
 }
 
 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.
+  // 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 ";
+  }
+
+  // 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 com.google.protobuf.Descriptors.Descriptor\n"
+    "  internal_$identifier$_descriptor;\n");
+
+  // And the FieldAccessorTable.
+  GenerateFieldAccessorTable(printer);
 
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -139,39 +144,42 @@
   }
 }
 
-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::
@@ -191,8 +199,9 @@
     "    internal_$identifier$_fieldAccessorTable;\n");
 }
 
-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"
@@ -203,6 +212,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);
@@ -210,51 +220,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<\n"
-        "              $classname$, $classname$.Builder> {\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();
@@ -263,6 +255,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");
@@ -279,98 +283,70 @@
   variables["static"] = is_own_file ? " " : " static ";
   variables["classname"] = descriptor_->name();
   variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
-  variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite";
 
   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(variables,
-        "public $static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
-        "      $classname$> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n");
-    } else {
-      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");
-    }
+    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$1.ExtendableBuilder<$0, ?>",
-             name_resolver_->GetImmutableClassName(descriptor_),
-             variables["lite"]);
+             "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
+             name_resolver_->GetImmutableClassName(descriptor_));
   } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(variables,
-        "public $static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n");
-    } 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 = strings::Substitute(
-        "com.google.protobuf.GeneratedMessage$0.Builder",
-        variables["lite"]);
+    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();
-  if (HasDescriptorMethods(descriptor_)) {
-    // Using builder_type, instead of Builder, prevents the Builder class from
-    // being loaded into PermGen space when the default instance is created.
-    // This optimizes the PermGen space usage for clients that do not modify
-    // messages.
-    printer->Print(
-      "// Use $classname$.newBuilder() to construct.\n"
-      "private $classname$($buildertype$ builder) {\n"
-      "  super(builder);\n"
-      "}\n",
-      "classname", descriptor_->name(),
-      "buildertype", builder_type);
-    printer->Print(
-      "private $classname$() {\n",
-      "classname", descriptor_->name());
-    printer->Indent();
-    GenerateInitializers(printer);
-    printer->Outdent();
-    printer->Print(
-      "}\n"
-      "\n");
-  }
+  // Using builder_type, instead of Builder, prevents the Builder class from
+  // being loaded into PermGen space when the default instance is created.
+  // This optimizes the PermGen space usage for clients that do not modify
+  // messages.
+  printer->Print(
+    "// Use $classname$.newBuilder() to construct.\n"
+    "private $classname$($buildertype$ builder) {\n"
+    "  super(builder);\n"
+    "}\n",
+    "classname", descriptor_->name(),
+    "buildertype", builder_type);
+  printer->Print(
+    "private $classname$() {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+  GenerateInitializers(printer);
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
+  printer->Print(
+    "@java.lang.Override\n"
+    "public final com.google.protobuf.UnknownFieldSet\n"
+    "getUnknownFields() {\n");
+  if (PreserveUnknownFields(descriptor_)) {
     printer->Print(
-      "@java.lang.Override\n"
-      "public final com.google.protobuf.UnknownFieldSet\n"
-      "getUnknownFields() {\n");
-    if (PreserveUnknownFields(descriptor_)) {
-      printer->Print(
-        "  return this.unknownFields;\n");
-    } else {
-      printer->Print(
-        "  return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
-    }
+      "  return this.unknownFields;\n");
+  } else {
     printer->Print(
-      "}\n");
+      "  return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
   }
+  printer->Print(
+    "}\n");
 
   if (HasGeneratedMethods(descriptor_)) {
     GenerateParsingConstructor(printer);
   }
 
-  GenerateDescriptorMethods(printer, false);
-  GenerateParser(printer);
+  GenerateDescriptorMethods(printer);
 
   // Nested types
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@@ -470,6 +446,10 @@
       "\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,7 +460,7 @@
   }
 
   if (HasGeneratedMethods(descriptor_)) {
-    GenerateIsInitialized(printer, MEMOIZE);
+    GenerateIsInitialized(printer);
     GenerateMessageSerializationMethods(printer);
   }
 
@@ -501,78 +481,39 @@
   // Carefully initialize the default instance in such a way that it doesn't
   // conflict with other initialization.
   printer->Print(
-    "private static final $classname$ defaultInstance;\n",
+    "private static final $classname$ DEFAULT_INSTANCE;\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "static {\n"
-      "  defaultInstance = new $classname$();\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE_RUNTIME only has one constructor.
-    printer->Print(
-      "static {\n"
-      "  defaultInstance = new $classname$(\n"
-      "      com.google.protobuf.Internal\n"
-      "          .EMPTY_CODED_INPUT_STREAM,\n"
-      "      com.google.protobuf.ExtensionRegistryLite\n"
-      "          .getEmptyRegistry());\n"
-      "}\n"
-      "\n",
-      "classname", descriptor_->name());
-  }
+  printer->Print(
+    "static {\n"
+    "  DEFAULT_INSTANCE = new $classname$();\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
   printer->Print(
       "public static $classname$ getDefaultInstance() {\n"
-      "  return defaultInstance;\n"
+      "  return DEFAULT_INSTANCE;\n"
       "}\n"
       "\n",
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-      "public $classname$ getDefaultInstanceForType() {\n"
-      "  return defaultInstance;\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE_RUNTIME uses this to implement the *ForType methods at the
-    // GeneratedMessageLite level.
-    printer->Print(
-      "static {"
-      "  com.google.protobuf.GeneratedMessageLite.onLoad(\n"
-      "      $classname$.class, new com.google.protobuf.GeneratedMessageLite\n"
-      "          .PrototypeHolder<$classname$, Builder>(\n"
-      "              defaultInstance, PARSER));"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
+  GenerateParser(printer);
 
-  // Extensions must be declared after the defaultInstance is initialized
-  // because the defaultInstance is used by the extension to lazily retrieve
+  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_)
         .Generate(printer);
   }
 
-  // Some fields also have static members that must be initialized after we
-  // have the default instance available.
-  printer->Print(
-      "static {\n");
-  printer->Indent();
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    field_generators_.get(descriptor_->field(i))
-        .GenerateStaticInitializationCode(printer);
-  }
-  printer->Outdent();
-  printer->Print(
-      "}\n");
-
   printer->Outdent();
   printer->Print("}\n\n");
 }
@@ -609,35 +550,17 @@
 
   if (descriptor_->extension_range_count() > 0) {
     if (descriptor_->options().message_set_wire_format()) {
-      if (HasDescriptorMethods(descriptor_)) {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessage\n"
-          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
-          "    extensionWriter = newMessageSetExtensionWriter();\n",
-          "classname", name_resolver_->GetImmutableClassName(descriptor_));
-      } else {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessageLite\n"
-          "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
-          "    .ExtensionWriter extensionWriter =\n"
-          "      newMessageSetExtensionWriter();\n",
-          "classname", name_resolver_->GetImmutableClassName(descriptor_));
-      }
+      printer->Print(
+        "com.google.protobuf.GeneratedMessage\n"
+        "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+        "    extensionWriter = newMessageSetExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
     } else {
-      if (HasDescriptorMethods(descriptor_)) {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessage\n"
-          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
-          "    extensionWriter = newExtensionWriter();\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_));
-      }
+      printer->Print(
+        "com.google.protobuf.GeneratedMessage\n"
+        "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+        "    extensionWriter = newExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
     }
   }
 
@@ -657,8 +580,7 @@
   }
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (descriptor_->options().message_set_wire_format()
-        && HasDescriptorMethods(descriptor_)) {
+    if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
         "unknownFields.writeAsMessageSetTo(output);\n");
     } else {
@@ -671,9 +593,8 @@
   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");
@@ -694,8 +615,7 @@
   }
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (descriptor_->options().message_set_wire_format()
-        && HasDescriptorMethods(descriptor_)) {
+    if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
         "size += unknownFields.getSerializedSizeAsMessageSet();\n");
     } else {
@@ -706,7 +626,7 @@
 
   printer->Outdent();
   printer->Print(
-    "  memoizedSerializedSize = size;\n"
+    "  memoizedSize = size;\n"
     "  return size;\n"
     "}\n"
     "\n");
@@ -744,34 +664,34 @@
     "}\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.parseWithIOException(PARSER, input);"
     "}\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.parseWithIOException(PARSER, input, extensionRegistry);"
     "}\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.parseDelimitedWithIOException(PARSER, input);"
     "}\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.parseDelimitedWithIOException(PARSER, input, extensionRegistry);"
     "}\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.parseWithIOException(PARSER, input);"
     "}\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.parseWithIOException(PARSER, input, extensionRegistry);"
     "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -792,609 +712,115 @@
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-      "public Builder newBuilderForType() { return newBuilder(); }\n");
-  }
+  // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+  printer->Print(
+    "public Builder newBuilderForType() { return newBuilder(); }\n");
 
   printer->Print(
     "public static Builder newBuilder() {\n"
-    "  return defaultInstance.toBuilder();\n"
+    "  return DEFAULT_INSTANCE.toBuilder();\n"
     "}\n"
     "public static Builder newBuilder($classname$ prototype) {\n"
-    "  return defaultInstance.toBuilder().mergeFrom(prototype);\n"
+    "  return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
     "}\n"
     "public Builder toBuilder() {\n"
-    "  return this == defaultInstance\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, true);
-  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);
-  }
-
-  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());
+    "@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, bool is_builder) {
-  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_));
-    }
-    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");
-      if (is_builder) {
-        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");
-      }
-    }
+GenerateDescriptorMethods(io::Printer* printer) {
+  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) {
-  if (HasDescriptorMethods(descriptor_)) {
-    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_));
-  } else {
-    // LITE runtime passes along the default instance to implement
-    // getDefaultInstanceForType() at the GeneratedMessageLite level.
-    printer->Print(
-        "// Construct using $classname$.newBuilder()\n"
-        "private Builder() {\n"
-        "  super(defaultInstance);\n"
-        "  maybeForceBuilderInitialization();\n"
-        "}\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(
-    "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");
-
-  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_));
-
-    // LITE runtime implements this in GeneratedMessageLite.
-    printer->Print(
-      "public $classname$ getDefaultInstanceForType() {\n"
-      "  return $classname$.getDefaultInstance();\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
   }
-
-  // -----------------------------------------------------------------
-
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE implements build in GeneratedMessageLite to save methods.
-    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_));
+  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 (HasDescriptorMethods(descriptor_)) {
+  if (!map_fields.empty()) {
     printer->Print(
-        "public $classname$ buildPartial() {\n"
-        "  $classname$ result = new $classname$(this);\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE_RUNTIME only provides a single message constructor.
-    printer->Print(
-        "public $classname$ buildPartial() {\n"
-        "  $classname$ result = new $classname$(\n"
-        "      com.google.protobuf.Internal\n"
-        "          .EMPTY_CODED_INPUT_STREAM,\n"
-        "      com.google.protobuf.ExtensionRegistryLite\n"
-        "          .getEmptyRegistry());\n"
-        "  result.unknownFields = this.unknownFields;\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-    if (descriptor_->extension_range_count() > 0) {
+      "@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(
-        "  result.extensions = this.buildExtensions();\n");
+        "case $number$:\n"
+        "  return internalGet$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
     }
-  }
-
-  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();
-
-  if (HasDescriptorMethods(descriptor_)) {
     printer->Print(
-    "  onBuilt();\n");
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
   }
-
   printer->Print(
-    "  return result;\n"
+    "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_));
-
-  // -----------------------------------------------------------------
-
-  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_));
-    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");
-    }
-
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print("  onChanged();\n");
-    }
-
-    printer->Print(
-      "  return this;\n"
-      "}\n"
-      "\n");
-  }
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateBuilderParsingMethods(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    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_));
-  }
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
 }
 
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateIsInitialized(
-    io::Printer* printer, UseMemoization useMemoization) {
-  // LITE_RUNTIME avoids generating isInitialized if it's not needed.
-  if (!HasDescriptorMethods(descriptor_)
-      && !HasRequiredFields(descriptor_)) {
-    return;
-  }
-
-  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
@@ -1406,11 +832,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);
     }
   }
 
@@ -1424,13 +849,12 @@
         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()) &&
@@ -1449,38 +873,35 @@
           }
           printer->Print(
             "  if (!get$name$().isInitialized()) {\n"
-            "    $memoize$\n"
+            "    memoizedIsInitialized = 0;\n"
             "    return false;\n"
             "  }\n"
             "}\n",
-            "name", info->capitalized_name,
-            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+            "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"
-              "    $memoize$\n"
+              "    memoizedIsInitialized = 0;\n"
               "    return false;\n"
               "  }\n"
               "}\n",
               "type", MapValueImmutableClassdName(field->message_type(),
                                                   name_resolver_),
-              "name", info->capitalized_name,
-              "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+              "name", info->capitalized_name);
           } else {
             printer->Print(
               "for (int i = 0; i < get$name$Count(); i++) {\n"
               "  if (!get$name$(i).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;
       }
@@ -1490,18 +911,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"
@@ -1544,22 +962,58 @@
   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");
+      }
     }
   }
+
+  // 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
@@ -1567,12 +1021,10 @@
     printer->Print(
       "result = result && unknownFields.equals(other.unknownFields);\n");
   }
-  if (HasDescriptorMethods(descriptor_)) {
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "result = result &&\n"
-        "    getExtensionFields().equals(other.getExtensionFields());\n");
-    }
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "result = result &&\n"
+      "    getExtensionFields().equals(other.getExtensionFields());\n");
   }
   printer->Print(
     "return result;\n");
@@ -1595,14 +1047,7 @@
     "}\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");
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
@@ -1620,11 +1065,9 @@
       printer->Print("}\n");
     }
   }
-  if (HasDescriptorMethods(descriptor_)) {
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "hash = hashFields(hash, getExtensionFields());\n");
-    }
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "hash = hashFields(hash, getExtensionFields());\n");
   }
 
   printer->Print(
@@ -1667,13 +1110,8 @@
   printer->Indent();
 
   // Initialize all fields to default.
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-        "this();\n");
-  } else {
-    // LITE_RUNTIME only has one constructor.
-    GenerateInitializers(printer);
-  }
+  printer->Print(
+      "this();\n");
 
   // Use builder bits to track mutable repeated fields.
   int totalBuilderBits = 0;
@@ -1689,15 +1127,9 @@
   }
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
-        "    com.google.protobuf.UnknownFieldSet.newBuilder();\n");
-    } else {
-      printer->Print(
-        "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
-        "    com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
-    }
+    printer->Print(
+      "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
+      "    com.google.protobuf.UnknownFieldSet.newBuilder();\n");
   }
 
   printer->Print(
@@ -1720,29 +1152,14 @@
     "  break;\n");
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (!HasDescriptorMethods(descriptor_)
-        && descriptor_->extension_range_count() > 0) {
-      // Lite runtime directly invokes parseUnknownField to reduce method
-      // counts.
-      printer->Print(
-        "default: {\n"
-        "  if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
-        "                         input, unknownFields,\n"
-        "                         extensionRegistry, tag)) {\n"
-        "    done = true;\n"  // it's an endgroup tag
-        "  }\n"
-        "  break;\n"
-        "}\n");
-    } else {
-      printer->Print(
-        "default: {\n"
-        "  if (!parseUnknownField(input, unknownFields,\n"
-        "                         extensionRegistry, tag)) {\n"
-        "    done = true;\n"  // it's an endgroup tag
-        "  }\n"
-        "  break;\n"
-        "}\n");
-    }
+    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"
@@ -1800,9 +1217,8 @@
       "} 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"
+      "  throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n"
+      "      .setUnfinishedMessage(this));\n"
       "} finally {\n");
   printer->Indent();
 
@@ -1817,18 +1233,9 @@
     printer->Print("this.unknownFields = unknownFields.build();\n");
   }
 
-  if (!HasDescriptorMethods(descriptor_)) {
-    // LITE runtime uses a static method to reduce method count.
-    if (descriptor_->extension_range_count() > 0) {
-      // Make extensions immutable.
-      printer->Print(
-          "makeExtensionsImmutable(extensions);\n");
-    }
-  } else {
-    // Make extensions immutable.
-    printer->Print(
-        "makeExtensionsImmutable();\n");
-  }
+  // Make extensions immutable.
+  printer->Print(
+      "makeExtensionsImmutable();\n");
 
   printer->Outdent();
   printer->Outdent();
@@ -1840,8 +1247,11 @@
 // ===================================================================
 void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
   printer->Print(
-      "public static final 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(
@@ -1866,9 +1276,9 @@
         "  }\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"
@@ -1878,7 +1288,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();
@@ -1890,16 +1301,17 @@
       "};\n"
       "\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-        "@java.lang.Override\n"
-        "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
-        "  return PARSER;\n"
-        "}\n"
-        "\n",
-        "classname", descriptor_->name());
-  }
+  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"
+      "}\n"
+      "\n",
+      "classname", descriptor_->name());
 }
 
 // ===================================================================
@@ -1913,6 +1325,50 @@
 }
 
 
+void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
+  printer->Print(
+    "private static String getTypeUrl(\n"
+    "    com.google.protobuf.Descriptors.Descriptor descriptor) {\n"
+    "  return \"type.googleapis.com/\" + descriptor.getFullName();\n"
+    "}\n"
+    "\n"
+    "public static <T extends com.google.protobuf.Message> Any pack(\n"
+    "    T message) {\n"
+    "  return Any.newBuilder()\n"
+    "      .setTypeUrl(getTypeUrl(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 getTypeUrl().equals(\n"
+    "      getTypeUrl(defaultInstance.getDescriptorForType()));\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
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 016fdd5..be5bfb0 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -67,8 +67,8 @@
   virtual void GenerateStaticVariables(io::Printer* printer) = 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;
@@ -97,16 +97,16 @@
   virtual void GenerateInterface(io::Printer* printer);
   virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
   virtual void GenerateStaticVariables(io::Printer* printer);
-  virtual void GenerateStaticVariableInitializers(io::Printer* printer);
+
+  // 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);
+
+  // 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,15 +116,13 @@
       io::Printer* printer, const Descriptor::ExtensionRange* range);
 
   void GenerateBuilder(io::Printer* printer);
-  void GenerateCommonBuilderMethods(io::Printer* printer);
-  void GenerateDescriptorMethods(io::Printer* printer, bool is_builder);
-  void GenerateBuilderParsingMethods(io::Printer* printer);
-  void GenerateIsInitialized(io::Printer* printer,
-      UseMemoization useMemoization);
+  void GenerateIsInitialized(io::Printer* printer);
+  void GenerateDescriptorMethods(io::Printer* printer);
   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..5d53503
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -0,0 +1,661 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_NE(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+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 (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.valueOf(\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 (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..8719d00
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.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.
+
+// 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_EQ(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+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);
+  }
+
+  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 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 a2d12a3..b5f8e62 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -157,11 +157,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::
@@ -182,14 +180,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 $name$_ == null ? $type$.getDefaultInstance() : $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 +198,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 +211,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(
@@ -260,14 +250,12 @@
   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".
@@ -368,40 +356,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"
-      "    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");
-  }
+  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::
@@ -466,11 +452,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_,
@@ -557,16 +543,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::
@@ -574,14 +558,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".
@@ -683,45 +665,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"
-      "  $on_changed$;\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::
@@ -756,11 +736,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_,
@@ -831,16 +812,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::
@@ -882,19 +862,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(
@@ -942,14 +918,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".
@@ -1116,70 +1090,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::
@@ -1261,11 +1233,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..356520e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -0,0 +1,946 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  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::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  merge$capitalized_name$(other.get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  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::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "merge$capitalized_name$(other.get$capitalized_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$_ = newProtobufList($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::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations (non-nested builder case):
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\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$_ = newProtobufList();\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..ae26c06
--- /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 GenerateMergingCode(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 GenerateMergingCode(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 GenerateMergingCode(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..94ed2c3
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -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.
+
+// 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.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_EQ(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
+
+void ImmutableMessageLiteGenerator::GenerateStaticVariables(
+    io::Printer* printer) {
+  // 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);
+  }
+}
+
+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();
+
+  GenerateParsingConstructor(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 int value = 0;\n"
+      "private $oneof_capitalized_name$Case(int value) {\n"
+      "  this.value = value;\n"
+      "}\n");
+    printer->Print(vars,
+      "public static $oneof_capitalized_name$Case valueOf(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: throw new java.lang.IllegalArgumentException(\n"
+      "      \"Value is undefined for this oneof enum.\");\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.valueOf(\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);
+
+  if (HasEqualsAndHashCode(descriptor_)) {
+    GenerateEqualsAndHashCode(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 PARSE_PARTIAL_FROM: {\n"
+    "      return new $classname$("
+    "          (com.google.protobuf.CodedInputStream) arg0,\n"
+    "          (com.google.protobuf.ExtensionRegistryLite) arg1);\n"
+    "    }\n"
+    "    case NEW_INSTANCE: {\n"
+    "      return new $classname$(\n"
+    "          com.google.protobuf.Internal.EMPTY_CODED_INPUT_STREAM,\n"
+    "          com.google.protobuf.ExtensionRegistryLite\n"
+    "              .getEmptyRegistry());\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 MERGE_FROM: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodMergeFrom(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"
+    "      com.google.protobuf.Internal\n"
+    "          .EMPTY_CODED_INPUT_STREAM,\n"
+    "      com.google.protobuf.ExtensionRegistryLite\n"
+    "          .getEmptyRegistry());\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++) {
+    ImmutableExtensionGenerator(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");
+
+  printer->Print(
+    "private static final long serialVersionUID = 0L;\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 parser().parseFrom(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 parser().parseFrom(data, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(byte[] data)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return parser().parseFrom(data);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    byte[] data,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return parser().parseFrom(data, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(java.io.InputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return parser().parseFrom(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"
+    "}\n"
+    "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return parser().parseDelimitedFrom(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"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.CodedInputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return parser().parseFrom(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"
+    "}\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::GenerateDynamicMethodMergeFrom(
+    io::Printer* printer) {
+  printer->Print(
+    // Optimization:  If other is the default instance, we know none of its
+    //   fields are set so we can skip the merge.
+    "if (arg0 == $classname$.getDefaultInstance()) return this;\n"
+    "$classname$ other = ($classname$) arg0;\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)).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");
+  }
+
+  // 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(
+    "return this;\n");
+}
+
+// ===================================================================
+
+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::
+GenerateEqualsAndHashCode(io::Printer* printer) {
+  printer->Print(
+    "@java.lang.Override\n"
+    "public boolean equals(final java.lang.Object obj) {\n");
+  printer->Indent();
+  printer->Print(
+    "if (obj == this) {\n"
+    " return true;\n"
+    "}\n"
+    "if (!(obj instanceof $classname$)) {\n"
+    "  return super.equals(obj);\n"
+    "}\n"
+    "$classname$ other = ($classname$) obj;\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  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 (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");
+  }
+  printer->Print(
+    "return result;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
+
+  printer->Print(
+    "@java.lang.Override\n"
+    "public int hashCode() {\n");
+  printer->Indent();
+  printer->Print(
+    "if (memoizedHashCode != 0) {\n");
+  printer->Indent();
+  printer->Print(
+    "return memoizedHashCode;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "int hash = 41;\n");
+
+  // 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_));
+
+  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");
+    }
+  }
+
+  printer->Print(
+    "hash = (29 * hash) + unknownFields.hashCode();\n");
+  printer->Print(
+    "memoizedHashCode = hash;\n"
+    "return hash;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateExtensionRegistrationCode(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionGenerator(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::
+GenerateParsingConstructor(io::Printer* printer) {
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+      SortFieldsByNumber(descriptor_));
+
+  printer->Print(
+      "private $classname$(\n"
+      "    com.google.protobuf.CodedInputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
+      "classname", descriptor_->name());
+  printer->Indent();
+
+  // Initialize all fields to default.
+  GenerateInitializers(printer);
+
+  // Use builder bits to track mutable repeated fields.
+  int totalBuilderBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const ImmutableFieldLiteGenerator& field =
+        field_generators_.get(descriptor_->field(i));
+    totalBuilderBits += field.GetNumBitsForBuilder();
+  }
+  int totalBuilderInts = (totalBuilderBits + 31) / 32;
+  for (int i = 0; i < totalBuilderInts; i++) {
+    printer->Print("int mutable_$bit_field_name$ = 0;\n",
+      "bit_field_name", GetBitFieldName(i));
+  }
+
+  printer->Print(
+      "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");
+  }
+
+  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();
+
+  // Make repeated field list immutable.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = sorted_fields[i];
+    field_generators_.get(field).GenerateParsingDoneCode(printer);
+  }
+
+  printer->Print(
+      "doneParsing();\n");
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+      "  }\n"     // finally
+      "}\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..2bd3cdd
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.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.
+
+// 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);
+  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 GenerateDynamicMethodMergeFrom(io::Printer* printer);
+  void GenerateDynamicMethodNewBuilder(io::Printer* printer);
+  void GenerateInitializers(io::Printer* printer);
+  void GenerateEqualsAndHashCode(io::Printer* printer);
+  void GenerateParser(io::Printer* printer);
+  void GenerateParsingConstructor(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_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 48757c6..178bbe1 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>
@@ -74,7 +75,12 @@
       "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
   (*variables)["capitalized_type"] =
       GetCapitalizedType(descriptor, /* immutable = */ true);
-  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  if (descriptor->is_packed()) {
+    (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag(
+        descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+  } else {
+    (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  }
   (*variables)["tag_size"] = SimpleItoa(
       WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
   if (IsReferenceType(GetJavaType(descriptor))) {
@@ -599,7 +605,7 @@
     "  return $name$_.get(index);\n"
     "}\n");
 
-  if (descriptor_->options().packed() &&
+  if (descriptor_->is_packed() &&
       HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize = -1;\n");
@@ -771,7 +777,7 @@
 
 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.
@@ -812,7 +818,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"
@@ -825,7 +831,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..5a7bf82
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -0,0 +1,911 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)["new_list"] = "new" + capitalized_type + "List";
+      (*variables)["new_list_with_capacity"] =
+          "new" + capitalized_type + "ListWithCapacity";
+      (*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;
+      break;
+    default:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal.ProtobufList<" +
+          (*variables)["boxed_type"] + ">";
+      (*variables)["new_list"] = "newProtobufList";
+      (*variables)["new_list_with_capacity"] = "newProtobufListWithCapacity";
+      (*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";
+  }
+
+  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);
+  }
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  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::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "if (other.has$capitalized_name$()) {\n"
+      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (other.get$capitalized_name$() != $default$) {\n"
+      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "}\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::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "set$capitalized_name$(other.get$capitalized_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() &&
+      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$_ = $new_list$($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::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations:
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\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$_ = $new_list$();\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$_ = $new_list$();\n");
+  } else {
+    printer->Print(variables_,
+      "  $name$_ = $new_list_with_capacity$(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..ad603c2
--- /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 GenerateMergingCode(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 GenerateMergingCode(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 GenerateMergingCode(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_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 8aa5699..7f757e4 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,6 +78,10 @@
       "  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
@@ -126,10 +131,6 @@
       GenerateSetBitToLocal(messageBitIndex);
 }
 
-bool CheckUtf8(const FieldDescriptor* descriptor) {
-  return descriptor->file()->options().java_string_check_utf8();
-}
-
 }  // namespace
 
 // ===================================================================
@@ -208,7 +209,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 +405,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 if (!HasDescriptorMethods(descriptor_->file())) {
@@ -413,7 +414,7 @@
     // spurious intermediary ByteString allocations, cutting overall allocations
     // in half.
     printer->Print(variables_,
-      "String s = input.readString();\n"
+      "java.lang.String s = input.readString();\n"
       "$set_has_field_bit_message$\n"
       "$name$_ = s;\n");
   } else {
@@ -433,7 +434,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");
 }
 
@@ -441,8 +442,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");
 }
 
@@ -665,7 +665,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_oneof_case_message$;\n"
       "$oneof_name$_ = s;\n");
   } else if (!HasDescriptorMethods(descriptor_->file())) {
@@ -674,7 +674,7 @@
     // spurious intermediary ByteString allocations, cutting overall allocations
     // in half.
     printer->Print(variables_,
-      "String s = input.readString();\n"
+      "java.lang.String s = input.readString();\n"
       "$set_oneof_case_message$;\n"
       "$oneof_name$_ = s;\n");
   } else {
@@ -689,7 +689,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");
 }
 
@@ -697,8 +697,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");
 }
 
@@ -774,12 +773,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::
@@ -940,14 +933,14 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-    "String s = input.readStringRequireUtf8();\n");
+    "java.lang.String s = input.readStringRequireUtf8();\n");
   } else if (!HasDescriptorMethods(descriptor_->file())) {
     // 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");
+    "java.lang.String s = input.readString();\n");
   } else {
     printer->Print(variables_,
     "com.google.protobuf.ByteString bs = input.readBytes();\n");
@@ -967,30 +960,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"
@@ -1000,21 +969,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::
@@ -1026,30 +984,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..eb5964b
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_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)
+// 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 " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  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"] =
+        "!get" + (*variables)["capitalized_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::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    // Allow a slight breach of abstraction here in order to avoid forcing
+    // all string fields to Strings when copying fields from a Message.
+    printer->Print(variables_,
+      "if (other.has$capitalized_name$()) {\n"
+      "  $set_has_field_bit_message$\n"
+      "  $name$_ = other.$name$_;\n"
+      "  $on_changed$\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (!other.get$capitalized_name$().isEmpty()) {\n"
+      "  $name$_ = other.$name$_;\n"
+      "  $on_changed$\n"
+      "}\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::
+GenerateMergingCode(io::Printer* printer) const {
+  // Allow a slight breach of abstraction here in order to avoid forcing
+  // all string fields to Strings when copying fields from a Message.
+  printer->Print(variables_,
+    "$set_oneof_case_message$;\n"
+    "$oneof_name$_ = other.$oneof_name$_;\n"
+    "$on_changed$\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$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList(\n"
+    "        $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::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations:
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\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$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n"
+    "}\n");
+  if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_.add(s);\n");
+  } else {
+    printer->Print(variables_,
+      "$name$_.add(bs);\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..4d9b4bd
--- /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 GenerateMergingCode(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 GenerateMergingCode(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 GenerateMergingCode(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.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc
index f934b05..c6e8dfe 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc
@@ -73,13 +73,45 @@
       "// enum $classname$\n",
       "classname", descriptor_->name());
 
+  const string classname = RenameJavaKeywords(descriptor_->name());
+
   // Start of container interface
+  // If generating intdefs, we use the container interface as the intdef if
+  // present. Otherwise, we just make an empty @interface parallel to the
+  // constants.
+  bool use_intdef = params_.generate_intdefs();
   bool use_shell_class = params_.java_enum_style();
-  if (use_shell_class) {
-    printer->Print(
-      "public interface $classname$ {\n",
-      "classname", RenameJavaKeywords(descriptor_->name()));
+  if (use_intdef) {
+    // @IntDef annotation so tools can enforce correctness
+    // Annotations will be discarded by the compiler
+    printer->Print("@java.lang.annotation.Retention("
+      "java.lang.annotation.RetentionPolicy.SOURCE)\n"
+      "@android.support.annotation.IntDef({\n");
     printer->Indent();
+    for (int i = 0; i < canonical_values_.size(); i++) {
+      const string constant_name =
+          RenameJavaKeywords(canonical_values_[i]->name());
+      if (use_shell_class) {
+        printer->Print("$classname$.$name$,\n",
+          "classname", classname,
+          "name", constant_name);
+      } else {
+        printer->Print("$name$,\n", "name", constant_name);
+      }
+    }
+    printer->Outdent();
+    printer->Print("})\n");
+  }
+  if (use_shell_class || use_intdef) {
+    printer->Print(
+      "public $at_for_intdef$interface $classname$ {\n",
+      "classname", classname,
+      "at_for_intdef", use_intdef ? "@" : "");
+    if (use_shell_class) {
+        printer->Indent();
+    } else {
+        printer->Print("}\n\n");
+    }
   }
 
   // Canonical values
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
index 8a59d32..7666db3 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -76,6 +76,10 @@
       internal::WireFormatLite::MakeTag(descriptor->number(),
           internal::WireFormat::WireTypeForFieldType(descriptor->type())));
   (*variables)["message_name"] = descriptor->containing_type()->name();
+  const EnumDescriptor* enum_type = descriptor->enum_type();
+  (*variables)["message_type_intdef"] = "@"
+      + ToJavaName(params, enum_type->name(), true,
+          enum_type->containing_type(), enum_type->file());
 }
 
 void LoadEnumValues(const Params& params,
@@ -116,8 +120,10 @@
 
 void EnumFieldGenerator::
 GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
-  printer->Print(variables_,
-    "public $type$ $name$;\n");
+  if (params_.generate_intdefs()) {
+    printer->Print(variables_, "$message_type_intdef$\n");
+  }
+  printer->Print(variables_, "public $type$ $name$;\n");
 
   if (params_.generate_has()) {
     printer->Print(variables_,
@@ -256,12 +262,22 @@
 
 void AccessorEnumFieldGenerator::
 GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+  printer->Print(variables_, "private int $name$_;\n");
+  if (params_.generate_intdefs()) {
+    printer->Print(variables_, "$message_type_intdef$\n");
+  }
   printer->Print(variables_,
-    "private int $name$_;\n"
     "public int get$capitalized_name$() {\n"
     "  return $name$_;\n"
     "}\n"
-    "public $message_name$ set$capitalized_name$(int value) {\n"
+    "public $message_name$ set$capitalized_name$(");
+  if (params_.generate_intdefs()) {
+    printer->Print(variables_,
+      "\n"
+      "    $message_type_intdef$ ");
+  }
+  printer->Print(variables_,
+    "int value) {\n"
     "  $name$_ = value;\n"
     "  $set_has$;\n"
     "  return this;\n"
@@ -499,6 +515,14 @@
 }
 
 void RepeatedEnumFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null && this.$name$.length > 0) {\n"
+    "  cloned.$name$ = this.$name$.clone();\n"
+    "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
index 00adc61..b94790d 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -106,6 +106,7 @@
   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:
   void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc
index 754ed55..0b9d1d8 100644
--- a/src/google/protobuf/compiler/javanano/javanano_extension.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -140,7 +140,7 @@
     "        com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n"
     "            com.google.protobuf.nano.Extension.$type$,\n"
     "            $class$.class,\n"
-    "            $tag_params$);\n");
+    "            $tag_params$L);\n");
 }
 
 }  // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
index c2cf091..57c221f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -83,6 +83,7 @@
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
   virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
   virtual void GenerateHashCodeCode(io::Printer* printer) const = 0;
+  virtual void GenerateFixClonedCode(io::Printer* printer) const {}
 
  protected:
   const Params& params_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index b5fbcd5..a33eba1 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -67,8 +67,15 @@
       file->name(), file->options().java_outer_classname());
   }
   if (file->options().has_java_package()) {
+    string result = file->options().java_package();
+    if (!file->options().javanano_use_deprecated_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(
@@ -152,6 +159,12 @@
       params.set_ignore_services(option_value == "true");
     } else if (option_name == "parcelable_messages") {
       params.set_parcelable_messages(option_value == "true");
+    } else if (option_name == "generate_clone") {
+      params.set_generate_clone(option_value == "true");
+    } else if (option_name == "generate_intdefs") {
+      params.set_generate_intdefs(option_value == "true");
+    } else if (option_name == "generate_clear") {
+      params.set_generate_clear(option_value == "true");
     } else {
       *error = "Ignore unknown javanano generator option: " + option_name;
     }
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index 0d2ae9d..5465655 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -200,6 +200,14 @@
       if (!result.empty()) result += '.';
       result += file->package();
     }
+
+    if (!file->options().javanano_use_deprecated_package()) {
+      if (!result.empty()) {
+        result += ".";
+      }
+      result += "nano";
+    }
+
     return result;
   }
 }
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index 707f6b8..a41da5a 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -136,21 +136,37 @@
   }
   if (params_.store_unknown_fields() && params_.parcelable_messages()) {
     printer->Print(
-      "    com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
+      "    com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$>",
       "classname", descriptor_->name());
   } else if (params_.store_unknown_fields()) {
     printer->Print(
-      "    com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+      "    com.google.protobuf.nano.ExtendableMessageNano<$classname$>",
       "classname", descriptor_->name());
   } else if (params_.parcelable_messages()) {
     printer->Print(
-      "    com.google.protobuf.nano.android.ParcelableMessageNano {\n");
+      "    com.google.protobuf.nano.android.ParcelableMessageNano");
   } else {
     printer->Print(
-      "    com.google.protobuf.nano.MessageNano {\n");
+      "    com.google.protobuf.nano.MessageNano");
+  }
+  if (params_.generate_clone()) {
+    printer->Print(" implements java.lang.Cloneable {\n");
+  } else {
+    printer->Print(" {\n");
   }
   printer->Indent();
 
+  if (params_.parcelable_messages()) {
+    printer->Print(
+      "\n"
+      "// Used by Parcelable\n"
+      "@SuppressWarnings({\"unused\"})\n"
+      "public static final android.os.Parcelable.Creator<$classname$> CREATOR =\n"
+      "    new com.google.protobuf.nano.android.ParcelableMessageNanoCreator<\n"
+      "        $classname$>($classname$.class);\n",
+      "classname", descriptor_->name());
+  }
+
   // Nested types and extensions
   for (int i = 0; i < descriptor_->extension_count(); i++) {
     ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
@@ -288,20 +304,28 @@
     }
     printer->Print("}\n");
   } else {
+    printer->Print(
+      "\n"
+      "public $classname$() {\n",
+      "classname", descriptor_->name());
     if (params_.generate_clear()) {
-      printer->Print(
-        "\n"
-        "public $classname$() {\n"
-        "  clear();\n"
-        "}\n",
-        "classname", descriptor_->name());
+      printer->Print("  clear();\n");
+    } else {
+      printer->Indent();
+      GenerateFieldInitializers(printer);
+      printer->Outdent();
     }
+    printer->Print("}\n");
   }
 
   // Other methods in this class
 
   GenerateClear(printer);
 
+  if (params_.generate_clone()) {
+    GenerateClone(printer);
+  }
+
   if (params_.generate_equals()) {
     GenerateEquals(printer);
     GenerateHashCode(printer);
@@ -495,6 +519,15 @@
     "classname", descriptor_->name());
   printer->Indent();
 
+  GenerateFieldInitializers(printer);
+
+  printer->Outdent();
+  printer->Print(
+    "  return this;\n"
+    "}\n");
+}
+
+void MessageGenerator::GenerateFieldInitializers(io::Printer* printer) {
   // Clear bit fields.
   int totalInts = (field_generators_.total_bits() + 31) / 32;
   for (int i = 0; i < totalInts; i++) {
@@ -520,12 +553,34 @@
   if (params_.store_unknown_fields()) {
     printer->Print("unknownFieldData = null;\n");
   }
+  printer->Print("cachedSize = -1;\n");
+}
+
+void MessageGenerator::GenerateClone(io::Printer* printer) {
+  printer->Print(
+    "@Override\n"
+    "public $classname$ clone() {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+
+  printer->Print(
+    "$classname$ cloned;\n"
+    "try {\n"
+    "  cloned = ($classname$) super.clone();\n"
+    "} catch (java.lang.CloneNotSupportedException e) {\n"
+    "  throw new java.lang.AssertionError(e);\n"
+    "}\n",
+    "classname", descriptor_->name());
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i)).GenerateFixClonedCode(printer);
+  }
 
   printer->Outdent();
   printer->Print(
-    "  cachedSize = -1;\n"
-    "  return this;\n"
-    "}\n");
+    "  return cloned;\n"
+    "}\n"
+    "\n");
 }
 
 void MessageGenerator::GenerateEquals(io::Printer* printer) {
@@ -568,7 +623,11 @@
 
   if (params_.store_unknown_fields()) {
     printer->Print(
-      "return unknownFieldDataEquals(other);\n");
+      "if (unknownFieldData == null || unknownFieldData.isEmpty()) {\n"
+      "  return other.unknownFieldData == null || other.unknownFieldData.isEmpty();\n"
+      "} else {\n"
+      "  return unknownFieldData.equals(other.unknownFieldData);\n"
+      "}");
   } else {
     printer->Print(
       "return true;\n");
@@ -598,7 +657,9 @@
 
   if (params_.store_unknown_fields()) {
     printer->Print(
-      "result = 31 * result + unknownFieldDataHashCode();\n");
+      "result = 31 * result + \n"
+      "  (unknownFieldData == null || unknownFieldData.isEmpty() ? 0 : \n"
+      "  unknownFieldData.hashCode());\n");
   }
 
   printer->Print("return result;\n");
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
index 6f25a3a..281ec64 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -77,8 +77,10 @@
                                  const FieldDescriptor* field);
 
   void GenerateClear(io::Printer* printer);
+  void GenerateFieldInitializers(io::Printer* printer);
   void GenerateEquals(io::Printer* printer);
   void GenerateHashCode(io::Printer* printer);
+  void GenerateClone(io::Printer* printer);
 
   const Params& params_;
   const Descriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
index 181c406..d1d04b5 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -127,6 +127,14 @@
 }
 
 void MessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null) {\n"
+    "  cloned.$name$ = this.$name$.clone();\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (this.$name$ == null) { \n"
@@ -213,6 +221,14 @@
 }
 
 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);
 }
@@ -313,6 +329,19 @@
 }
 
 void RepeatedMessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null && this.$name$.length > 0) {\n"
+    "  cloned.$name$ = new $type$[this.$name$.length];\n"
+    "  for (int i = 0; i < this.$name$.length; i++) {\n"
+    "    if (this.$name$[i] != null) {\n"
+    "      cloned.$name$[i] = this.$name$[i].clone();\n"
+    "    }\n"
+    "  }\n"
+    "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
index 6c615f5..e074735 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -58,6 +58,7 @@
   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_;
@@ -80,6 +81,7 @@
   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_;
@@ -102,6 +104,7 @@
   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_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
index 4691f36..e3b4bb9 100644
--- a/src/google/protobuf/compiler/javanano/javanano_params.h
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -66,6 +66,8 @@
   bool parcelable_messages_;
   bool reftypes_primitive_enums_;
   bool generate_clear_;
+  bool generate_clone_;
+  bool generate_intdefs_;
 
  public:
   Params(const string & base_name) :
@@ -81,7 +83,9 @@
     ignore_services_(false),
     parcelable_messages_(false),
     reftypes_primitive_enums_(false),
-    generate_clear_(true) {
+    generate_clear_(true),
+    generate_clone_(false),
+    generate_intdefs_(false) {
   }
 
   const string& base_name() const {
@@ -231,6 +235,20 @@
   bool generate_clear() const {
     return generate_clear_;
   }
+
+  void set_generate_clone(bool value) {
+    generate_clone_ = value;
+  }
+  bool generate_clone() const {
+    return generate_clone_;
+  }
+
+  void set_generate_intdefs(bool value) {
+    generate_intdefs_ = value;
+  }
+  bool generate_intdefs() const {
+    return generate_intdefs_;
+  }
 };
 
 }  // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index 41bad0a..978abf2 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -364,6 +364,14 @@
   }
 }
 
+void RepeatedPrimitiveFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null && this.$name$.length > 0) {\n"
+    "  cloned.$name$ = this.$name$.clone();\n"
+    "}\n");
+}
+
 void PrimitiveFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   // We define equality as serialized form equality. If generate_has(),
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
index ca7116f..a01981d 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -131,6 +131,7 @@
   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:
   void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
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..e6c3b36
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -0,0 +1,2622 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 {
+
+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.
+string StripProto(const string& filename) {
+  const char* suffix = HasSuffixString(filename, ".protodevel")
+      ? ".protodevel" : ".proto";
+  return StripSuffixString(filename, suffix);
+}
+
+// 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();
+}
+
+// - 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;
+}
+
+// Returns the message/response ID, if set.
+string GetMessageId(const Descriptor* desc) {
+  return string();
+}
+
+
+// Used inside Google only -- do not remove.
+bool IsResponse(const Descriptor* desc) { return false; }
+bool IgnoreField(const FieldDescriptor* field) { return false; }
+
+
+// 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;
+}
+
+// Returns the field name as a capitalized portion of a getter/setter method
+// name, e.g. MyField for .getMyField().
+string JSGetterName(const FieldDescriptor* field) {
+  string name = JSIdent(field,
+                        /* is_upper_camel = */ true,
+                        /* is_map = */ false);
+  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. Since JS strings are UTF-16, we only
+// need to handle the BMP (16-bit range) here.
+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. |is_utf8| determines whether the input data (in a C++ string of
+// chars) is UTF-8 encoded (in which case codepoints become JavaScript string
+// characters, escaped with 16-bit hex escapes where necessary) or raw binary
+// (in which case bytes become JavaScript string characters 0 -- 255).
+string EscapeJSString(const string& in, bool is_utf8) {
+  string result;
+  size_t decoded = 0;
+  for (size_t i = 0; i < in.size(); i += decoded) {
+    uint16 codepoint = 0;
+    if (is_utf8) {
+      // 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) {
+        break;
+      }
+      decoded = have_bytes;
+    } else {
+      codepoint = static_cast<uint16>(static_cast<uint8>(in[i]));
+      decoded = 1;
+    }
+
+    // Next byte -- used for minimal octal escapes below.
+    char next_byte = (i + decoded) < in.size() ?
+        in[i + decoded] : 0;
+    bool pad_octal = (next_byte >= '0' && next_byte <= '7');
+
+    switch (codepoint) {
+      case '\0': result += pad_octal ? "\\000" : "\\0";   break;
+      case '\b': result += "\\\b";  break;
+      case '\t': result += "\\\t";  break;
+      case '\n': result += "\\\n";  break;
+      case '\r': result += "\\\r";  break;
+      case '\f': result += "\\\f";  break;
+      case '\\': result += "\\\\";  break;
+      case '"':  result += pad_octal ? "\\042" : "\\42"; break;
+      case '&':  result += pad_octal ? "\\046" : "\\46"; break;
+      case '\'': result += pad_octal ? "\\047" : "\\47"; break;
+      case '<':  result += pad_octal ? "\\074" : "\\74"; break;
+      case '=':  result += pad_octal ? "\\075" : "\\75"; break;
+      case '>':  result += pad_octal ? "\\076" : "\\76"; break;
+      default:
+        // All other non-ASCII codepoints are escaped.
+        // Original codegen uses hex for >= 0x100 and octal for others.
+        if (codepoint >= 0x20 && codepoint <= 0x7e) {
+          result += static_cast<char>(codepoint);
+        } else {
+          if (codepoint >= 0x100) {
+            result += StringPrintf("\\u%04x", codepoint);
+          } else {
+            if (pad_octal || codepoint >= 0100) {
+              result += "\\";
+              result += ('0' + ((codepoint >> 6) & 07));
+              result += ('0' + ((codepoint >> 3) & 07));
+              result += ('0' + ((codepoint >> 0) & 07));
+            } else if (codepoint >= 010) {
+              result += "\\";
+              result += ('0' + ((codepoint >> 3) & 07));
+              result += ('0' + ((codepoint >> 0) & 07));
+            } else {
+              result += "\\";
+              result += ('0' + ((codepoint >> 0) & 07));
+            }
+          }
+        }
+        break;
+    }
+  }
+  return result;
+}
+
+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) {
+        return "\"" + EscapeJSString(field->default_value_string(), true) +
+               "\"";
+      } else {
+        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 JSTypeName(const GeneratorOptions& options,
+                  const FieldDescriptor* field) {
+  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 "string";
+    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,
+                             bool always_singular) {
+  bool is_primitive =
+      (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
+       field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE);
+
+  string jstype = JSTypeName(options, field);
+
+  if (field->is_repeated() &&
+      !always_singular &&
+      (field->is_packed() || !singular_if_not_packed)) {
+    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 (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) {
+    // Override for `bytes` fields: treat string as raw bytes, not base64.
+    name = "BytesRawString";
+  }
+  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 Descriptor* desc) {
+  if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
+    return "jspb.Message.messageSetExtensions";
+  } else {
+    return GetPath(options, 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) {
+  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";
+  }
+  return comments;
+}
+
+bool ShouldGenerateExtension(const FieldDescriptor* field) {
+  return
+      field->is_extension() &&
+      !IgnoreField(field);
+}
+
+bool HasExtensions(const Descriptor* desc) {
+  if (desc->extension_count() > 0) {
+    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 https://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 https://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:
+      return "\"\"";
+
+    default:
+      // BYTES and MESSAGE are handled separately.
+      assert(false);
+      return "";
+  }
+}
+
+}  // 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::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++) {
+    for (int j = 0; j < files[i]->message_type_count(); j++) {
+      FindProvidesForMessage(options, printer, files[i]->message_type(j),
+                                 provided);
+    }
+    for (int j = 0; j < files[i]->enum_type_count(); j++) {
+      FindProvidesForEnum(options, printer, files[i]->enum_type(j),
+                              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::GenerateRequires(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::GenerateRequires(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const vector<const FileDescriptor*>& files,
+                                 std::set<string>* provided) const {
+  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::GenerateRequires(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);
+    }
+  }
+
+  // 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),
+        "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", GetPath(options, field->message_type()));
+      }
+    } else {
+      printer->Print("(f = msg.get$getter$()) && "
+                     "$type$.toObject(includeInstance, f)",
+                     "getter", JSGetterName(field),
+                     "type", GetPath(options, field->message_type()));
+    }
+  } else {
+    // Simple field (singular or repeated).
+    if (!HasFieldPresence(field) && !field->is_repeated()) {
+      // Delegate to the generated get<field>() method in order not to duplicate
+      // the proto3-field-default-value logic here.
+      printer->Print("msg.get$getter$()",
+                     "getter", JSGetterName(field));
+    } else {
+      if (field->has_default_value()) {
+        printer->Print("jspb.Message.getField(msg, $index$) != null ? "
+                       "jspb.Message.getField(msg, $index$) : $defaultValue$",
+                       "index", JSFieldIndex(field),
+                       "defaultValue", JSFieldDefault(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", GetPath(options, field->message_type()));
+      }
+    } 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", GetPath(options, field->message_type()));
+    }
+  } 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 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),
+        "type", JSFieldTypeAnnotation(options, field,
+                                      /* force_optional = */ false,
+                                      /* force_present = */ false,
+                                      /* singular_if_not_packed = */ false,
+                                      /* always_singular = */ 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,
+                                      /* always_singular = */ false),
+        "rpt", (field->is_repeated() ? "Repeated" : ""),
+        "index", JSFieldIndex(field),
+        "wrapperclass", GetPath(options, field->message_type()),
+        "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,
+                              /* always_singular = */ 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 {
+    string typed_annotation;
+
+    // Simple (primitive) field, either singular or repeated.
+    {
+      typed_annotation = JSFieldTypeAnnotation(options, field,
+                              /* force_optional = */ false,
+                              /* force_present = */ !HasFieldPresence(field),
+                              /* singular_if_not_packed = */ false,
+                              /* always_singular = */ false),
+      printer->Print(
+          "/**\n"
+          " * $fielddef$\n"
+          "$comment$"
+          " * @return {$type$}\n"
+          " */\n",
+          "fielddef", FieldDefinition(options, field),
+          "comment", FieldComments(field),
+          "type", typed_annotation);
+    }
+
+    printer->Print(
+        "$class$.prototype.get$name$ = function() {\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field));
+
+    {
+      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 ? "
+                       "jspb.Message.getField(this, $index$) : $defaultValue$",
+                       "index", JSFieldIndex(field),
+                       "defaultValue", JSFieldDefault(field));
+      } else {
+        printer->Print("jspb.Message.getField(this, $index$)",
+                       "index", JSFieldIndex(field));
+      }
+    }
+
+    {
+      printer->Print(
+          ");\n"
+          "};\n"
+          "\n"
+          "\n");
+    }
+
+    {
+      printer->Print(
+          "/** @param {$optionaltype$} value $returndoc$ */\n",
+          "optionaltype",
+          JSFieldTypeAnnotation(options, field,
+                                /* force_optional = */ true,
+                                /* force_present = */ !HasFieldPresence(field),
+                                /* singular_if_not_packed = */ false,
+                                /* always_singular = */ 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", "",
+        "typeclose", "",
+        "oneofgroup",
+        (field->containing_oneof() ? (", " + JSOneofArray(options, field))
+                                   : ""),
+        "returnvalue", JSReturnClause(field), "rptvalueinit",
+        (field->is_repeated() ? " || []" : ""));
+
+
+    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),
+        "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", GetPath(options, field->message_type()),
+        "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,
+                                           /* always_singular = */ false),
+        "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$().
+    printer->Print(
+        "      msg.get$name$().push(value);\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),
+        "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));
+
+  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),
+      "name", JSGetterName(field),
+      "index", SimpleItoa(field->number()));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        ",\n"
+        "      $submsg$.serializeBinaryToWriter\n",
+        "submsg", GetPath(options, field->message_type()));
+  } 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,
+          /* always_singular = */ 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 ?
+               GetPath(options, field->message_type()) : string("null")),
+      "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+                   (GetPath(options, field->message_type()) + ".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) ?
+        (GetPath(options, field->message_type()) +
+         ".serializeBinaryToWriter") : "null",
+        "binaryMessageDeserializeFn",
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+        (GetPath(options, field->message_type()) +
+         ".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->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 {
+      // 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;
+    }
+  }
+
+  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);
+  }
+}
+
+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;
+  }
+
+
+  // We're either generating a single library file with definitions for message
+  // and enum types in *all* FileDescriptor inputs, or we're generating a single
+  // file for each type.
+  if (options.library != "") {
+    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);
+    GenerateRequires(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 {
+    // Collect all types, and print each type to a separate file. Pull out
+    // free-floating extensions while we make this pass.
+    map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
+
+    // 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.
+
+    // Current descriptor that will generate each filename, indexed by filename.
+    map<string, const void*> desc_by_filename;
+    // Set of descriptors allowed to generate files.
+    set<const void*> allowed_descs;
+
+    for (int i = 0; i < files.size(); i++) {
+      // Collect all (descriptor, filename) pairs.
+      map<const void*, string> descs_in_file;
+      for (int j = 0; j < files[i]->message_type_count(); j++) {
+        const Descriptor* desc = files[i]->message_type(j);
+        string filename =
+            options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+        descs_in_file[desc] = filename;
+      }
+      for (int j = 0; j < files[i]->enum_type_count(); j++) {
+        const EnumDescriptor* desc = files[i]->enum_type(j);
+        string filename =
+            options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+        descs_in_file[desc] = filename;
+      }
+
+      // For each (descriptor, filename) pair, update the
+      // descriptors-by-filename map, and if a previous descriptor was already
+      // writing the filename, remove it from the allowed-descriptors set.
+      map<const void*, string>::iterator it;
+      for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) {
+        const void* desc = it->first;
+        const string& filename = it->second;
+        if (desc_by_filename.find(filename) != desc_by_filename.end()) {
+          if (options.error_on_name_conflict) {
+            *error = "Name conflict: file name " + filename +
+                     " would be generated by two descriptors";
+            return false;
+          }
+          allowed_descs.erase(desc_by_filename[filename]);
+        }
+        desc_by_filename[filename] = desc;
+        allowed_descs.insert(desc);
+      }
+    }
+
+    // Generate code.
+    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_descs.find(desc) == allowed_descs.end()) {
+          continue;
+        }
+
+        string filename = options.output_dir + "/" +
+            ToFileName(desc->name()) + ".js";
+        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);
+        GenerateRequires(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_descs.find(enumdesc) == allowed_descs.end()) {
+          continue;
+        }
+
+        string filename = options.output_dir + "/" +
+            ToFileName(enumdesc->name()) + ".js";
+
+        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;
+        }
+      }
+      // Pull out all free-floating extensions and generate files for those too.
+      for (int j = 0; j < file->extension_count(); j++) {
+        const FieldDescriptor* extension = file->extension(j);
+        extensions_by_namespace[GetPath(options, files[i])]
+            .push_back(extension);
+      }
+    }
+
+    // Generate extensions in separate files.
+    map< string, vector<const FieldDescriptor*> >::iterator it;
+    for (it = extensions_by_namespace.begin();
+         it != extensions_by_namespace.end();
+         ++it) {
+      string filename = options.output_dir + "/" +
+          ToFileName(it->first) + ".js";
+
+      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;
+      FindProvidesForFields(options, &printer, it->second, &provided);
+      GenerateProvides(options, &printer, &provided);
+      GenerateTestOnly(options, &printer);
+      GenerateRequires(options, &printer, it->second, &provided);
+
+      for (int j = 0; j < it->second.size(); j++) {
+        if (ShouldGenerateExtension(it->second[j])) {
+          GenerateExtension(options, &printer, it->second[j]);
+        }
+      }
+    }
+  }
+
+  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..db2dceb
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -0,0 +1,265 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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;
+
+  GeneratorOptions()
+      : add_require_for_enums(false),
+        testonly(false),
+        output_dir("."),
+        namespace_prefix(""),
+        library(""),
+        error_on_name_conflict(false),
+        binary(false) {}
+
+  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 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 GenerateRequires(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const vector<const FileDescriptor*>& file,
+                        std::set<string>* provided) const;
+  void GenerateRequires(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const Descriptor* desc,
+                        std::set<string>* provided) const;
+  // For extension fields at file scope.
+  void GenerateRequires(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;
+
+  // 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 931b8fa..97df536 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -36,6 +36,9 @@
 #include <google/protobuf/compiler/java/java_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[]) {
 
@@ -68,5 +71,20 @@
   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_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 9826143..121d917 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -147,6 +147,12 @@
         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;
       }
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..d6f01c6
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
@@ -0,0 +1,198 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 GPB_ENUM($name$) {\n",
+                 "comments", enum_comments,
+                 "name", name_);
+  printer->Indent();
+
+  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    // Include the unknown value.
+    printer->Print(
+      "$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$ = $value$,\n",
+        "name", EnumValueName(all_values_[i]),
+        "value", SimpleItoa(all_values_[i]->number()));
+  }
+  printer->Outdent();
+  printer->Print(
+      "};\n"
+      "\n"
+      "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n"
+      "\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_);
+
+  printer->Print(
+      "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n"
+      "  static GPBEnumDescriptor *descriptor = NULL;\n"
+      "  if (!descriptor) {\n"
+      "    static GPBMessageEnumValueDescription values[] = {\n",
+      "name", name_);
+  printer->Indent();
+  printer->Indent();
+  printer->Indent();
+
+  // 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;
+
+  for (int i = 0; i < all_values_.size(); i++) {
+    ++enum_value_description_key;
+    string short_name(EnumValueShortName(all_values_[i]));
+    printer->Print("{ .name = \"$short_name$\", .number = $name$ },\n",
+                   "short_name", short_name,
+                   "name", EnumValueName(all_values_[i]));
+    if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) {
+      text_format_decode_data.AddString(enum_value_description_key, short_name,
+                                        all_values_[i]->name());
+    }
+  }
+  printer->Outdent();
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print("    };\n");
+  if (text_format_decode_data.num_entries() == 0) {
+    printer->Print(
+        "    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+        "                                                   values:values\n"
+        "                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n"
+        "                                             enumVerifier:$name$_IsValidValue];\n",
+        "name", name_);
+    } else {
+      printer->Print(
+        "    static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
+        "    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+        "                                                   values:values\n"
+        "                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n"
+        "                                             enumVerifier:$name$_IsValidValue\n"
+        "                                      extraTextFormatInfo:extraTextFormatInfo];\n",
+        "name", name_,
+        "extraTextFormatInfo", CEscape(text_format_decode_data.Data()));
+    }
+    printer->Print(
+      "  }\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..30a13dd
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_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 <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";
+
+  const Descriptor* msg_descriptor = descriptor->containing_type();
+  (*variables)["owning_message_class"] = ClassName(msg_descriptor);
+}
+}  // namespace
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor)
+    : SingleFieldGenerator(descriptor) {
+  SetEnumVariables(descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::GenerateFieldDescriptionTypeSpecific(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "  .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n");
+}
+
+void EnumFieldGenerator::GenerateCFunctionDeclarations(
+    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"
+      "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 {
+  // 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)
+    : RepeatedFieldGenerator(descriptor) {
+  SetEnumVariables(descriptor, &variables_);
+  variables_["array_storage_type"] = "GPBEnumArray";
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "  .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\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..b629eae
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.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_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);
+
+ public:
+  virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+  virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+  virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ protected:
+  explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~EnumFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ public:
+  virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+
+ protected:
+  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+  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..4e34839
--- /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"
+                 "  .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n"
+                 "  .dataType = $extension_type$,\n"
+                 "  .extendedClass = GPBStringifySymbol($extended_type$),\n"
+                 "  .fieldNumber = $number$,\n"
+                 "  .defaultValue.$default_name$ = $default$,\n"
+                 "  .messageOrGroupClassName = $type$,\n"
+                 "  .options = $options$,\n"
+                 "  .enumDescriptorFunc = $enum_desc_func_name$,\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..cf5d8cf
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -0,0 +1,434 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_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)["has_index"] = SimpleItoa(descriptor->index());
+  (*variables)["field_type"] = GetCapitalizedType(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";
+
+  string field_options = descriptor->options().SerializeAsString();
+  // Must convert to a standard byte order for packing length into
+  // a cstring.
+  uint32 length = ghtonl(field_options.length());
+  if (length > 0) {
+    string bytes((const char*)&length, sizeof(length));
+    bytes.append(field_options);
+    string options_str = "\"" + CEscape(bytes) + "\"";
+    (*variables)["fieldoptions"] = "\"" + CEscape(bytes) + "\"";
+  } else {
+    (*variables)["fieldoptions"] = "";
+  }
+
+  // Clear some common things so they can be set just when needed.
+  (*variables)["storage_attribute"] = "";
+}
+
+}  // namespace
+
+FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) {
+  FieldGenerator* result = NULL;
+  if (field->is_repeated()) {
+    switch (GetObjectiveCType(field)) {
+      case OBJECTIVECTYPE_MESSAGE: {
+        if (field->is_map()) {
+          result = new MapFieldGenerator(field);
+        } else {
+          result = new RepeatedMessageFieldGenerator(field);
+        }
+        break;
+      }
+      case OBJECTIVECTYPE_ENUM:
+        result = new RepeatedEnumFieldGenerator(field);
+        break;
+      default:
+        result = new RepeatedPrimitiveFieldGenerator(field);
+        break;
+    }
+  } else {
+    switch (GetObjectiveCType(field)) {
+      case OBJECTIVECTYPE_MESSAGE: {
+        result = new MessageFieldGenerator(field);
+        break;
+      }
+      case OBJECTIVECTYPE_ENUM:
+        result = new EnumFieldGenerator(field);
+        break;
+      default:
+        if (IsReferenceType(field)) {
+          result = new PrimitiveObjFieldGenerator(field);
+        } else {
+          result = new PrimitiveFieldGenerator(field);
+        }
+        break;
+    }
+  }
+  result->FinishInitialization();
+  return result;
+}
+
+
+FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor)
+    : 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) const {
+  printer->Print(
+      variables_,
+      "{\n"
+      "  .name = \"$name$\",\n"
+      "  .number = $field_number_name$,\n"
+      "  .hasIndex = $has_index$,\n"
+      "  .flags = $fieldflags$,\n"
+      "  .dataType = GPBDataType$field_type$,\n"
+      "  .offset = offsetof($classname$__storage_, $name$),\n"
+      "  .defaultValue.$default_name$ = $default$,\n");
+
+  // TODO(thomasvl): It might be useful to add a CPP wrapper to support
+  // compiling away the EnumDescriptors.  To do that, we'd need a #if here
+  // to control setting the descriptor vs. the validator, and above in
+  // SetCommonFieldVariables() we'd want to wrap how we add
+  // GPBFieldHasDefaultValue to the flags.
+
+  // "  .dataTypeSpecific.value* = [something],"
+  GenerateFieldDescriptionTypeSpecific(printer);
+
+  const string& field_options(variables_.find("fieldoptions")->second);
+  if (field_options.empty()) {
+    printer->Print("  .fieldOptions = NULL,\n");
+  } else {
+    // Can't use PrintRaw() here to get the #if/#else/#endif lines completely
+    // outdented because the need for indent captured on the previous
+    // printing of a \n and there is no way to get the current indent level
+    // to call the right number of Outdent()/Indents() to maintain state.
+    printer->Print(
+        variables_,
+        "#if GPBOBJC_INCLUDE_FIELD_OPTIONS\n"
+        "  .fieldOptions = $fieldoptions$,\n"
+        "#else\n"
+        "  .fieldOptions = NULL,\n"
+        "#endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS\n");
+  }
+
+  printer->Print("},\n");
+}
+
+void FieldGenerator::GenerateFieldDescriptionTypeSpecific(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "  .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n");
+}
+
+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)
+    : FieldGenerator(descriptor) {
+  // 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$");
+  if (WantsHasProperty()) {
+    printer->Print(
+        variables_,
+        "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n");
+  }
+  printer->Print(
+      variables_,
+      "@property(nonatomic, readwrite) $property_type$ $name$;\n"
+      "\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;
+}
+
+ObjCObjFieldGenerator::ObjCObjFieldGenerator(
+    const FieldDescriptor* descriptor)
+    : SingleFieldGenerator(descriptor) {
+  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$");
+  if (WantsHasProperty()) {
+    printer->Print(
+        variables_,
+        "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n");
+  }
+  printer->Print(
+      variables_,
+      "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_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;\n");
+  }
+  printer->Print("\n");
+}
+
+RepeatedFieldGenerator::RepeatedFieldGenerator(
+    const FieldDescriptor* descriptor)
+    : ObjCObjFieldGenerator(descriptor) {
+  // Repeated fields don't use the has index.
+  variables_["has_index"] = "GPBNoHasBit";
+}
+
+RepeatedFieldGenerator::~RepeatedFieldGenerator() {}
+
+void RepeatedFieldGenerator::FinishInitialization(void) {
+  FieldGenerator::FinishInitialization();
+  variables_["array_comment"] =
+      "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n";
+}
+
+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_storage_type$ *$name$$storage_attribute$;\n"
+      "@property(nonatomic, readonly) NSUInteger $name$_Count;\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_storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
+  }
+  printer->Print("\n");
+}
+
+bool RepeatedFieldGenerator::WantsHasProperty(void) const {
+  // Consumer check the array size/existance rather than a has bit.
+  return false;
+}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+    : 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)));
+  }
+  for (int i = 0; i < descriptor->extension_count(); i++) {
+    extension_generators_[i].reset(FieldGenerator::Make(descriptor->extension(i)));
+  }
+}
+
+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];
+}
+
+void FieldGeneratorMap::SetOneofIndexBase(int index_base) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_[i]->SetOneofIndexBase(index_base);
+  }
+}
+
+}  // 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..130a52d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.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_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);
+
+  virtual ~FieldGenerator();
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0;
+
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0;
+
+  virtual void GenerateFieldDescription(io::Printer* printer) const;
+  virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+  virtual void GenerateFieldNumberConstant(io::Printer* printer) const;
+
+  virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+  virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+  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:
+  explicit FieldGenerator(const FieldDescriptor* descriptor);
+
+  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;
+
+ protected:
+  explicit SingleFieldGenerator(const FieldDescriptor* descriptor);
+  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:
+  explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor);
+
+ 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;
+
+ protected:
+  explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor);
+  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:
+  explicit FieldGeneratorMap(const Descriptor* descriptor);
+  ~FieldGeneratorMap();
+
+  const FieldGenerator& get(const FieldDescriptor* field) const;
+  const FieldGenerator& get_extension(int index) const;
+
+  void SetOneofIndexBase(int index_base);
+
+ 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..228c66f
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -0,0 +1,368 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 = 30000;
+
+namespace compiler {
+namespace objectivec {
+
+FileGenerator::FileGenerator(const FileDescriptor *file)
+    : file_(file),
+      root_class_name_(FileClassName(file)),
+      is_public_dep_(false) {
+  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));
+    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"
+      "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"
+      "@interface $root_class_name$ : GPBRootObject\n"
+      "\n"
+      "// The base class provides:\n"
+      "//   + (GPBExtensionRegistry *)extensionRegistry;\n"
+      "// which is an GPBExtensionRegistry that includes all the extensions defined by\n"
+      "// this file and all files that it depends on.\n"
+      "\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"
+      "// @@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");
+
+  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"
+    "// @@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));
+      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..1bb4f0e
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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:
+  explicit FileGenerator(const FileDescriptor* file);
+  ~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 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..375b4e0
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -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.
+
+#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 {
+  // ObjC doesn't have any options at the moment, error if passed one.
+  vector<pair<string, string> > options;
+  ParseGeneratorParameter(parameter, &options);
+  for (int i = 0; i < options.size(); i++) {
+    *error = "error:: Unknown generator option: " + options[i].first;
+    return false;
+  }
+
+  // Validate the objc prefix/package pairing.
+  if (!ValidateObjCClassPrefix(file, error)) {
+    // *error will have been filled in.
+    return false;
+  }
+
+  FileGenerator file_generator(file);
+  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..8527b74
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -0,0 +1,1238 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 {
+
+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);
+
+  for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
+    string value = *i;
+    bool all_upper = (kUpperSegments.count(value) > 0);
+    for (int j = 0; j < value.length(); j++) {
+      if (j == 0 || all_upper) {
+        value[j] = ascii_toupper(value[j]);
+      } else {
+        // Nothing, already in lower.
+      }
+    }
+    *i = value;
+  }
+  string result;
+  for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
+    result += *i;
+  }
+  if ((result.length() != 0) && !first_capitalized) {
+    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();
+  }
+}
+
+// Escape C++ trigraphs by escaping question marks to \?
+string EscapeTrigraphs(const string& to_escape) {
+  return StringReplace(to_escape, "?", "\\?", true);
+}
+
+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
+
+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*)\"" + 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;
+}
+
+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++) {
+    // We use $ for delimiters, so replace comments with dollars with
+    // html escaped version.
+    // None of the other compilers handle this (as of this writing) but we
+    // ran into it once, so just to be safe.
+    final_comments +=
+        prefix + StringReplace(lines[i], "$", "&#36;", 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(map<string, string>* prefix_map,
+                                 string* out_expect_file_path,
+                                 string* out_error) {
+  const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
+  if (file_path == NULL) {
+    return true;
+  }
+
+  int fd;
+  do {
+    fd = open(file_path, O_RDONLY);
+  } while (fd < 0 && errno == EINTR);
+  if (fd < 0) {
+    *out_error =
+        string(file_path) + ":0:0: error: Unable to open." + strerror(errno);
+    return false;
+  }
+  io::FileInputStream file_stream(fd);
+  file_stream.SetCloseOnDelete(true);
+  *out_expect_file_path = file_path;
+
+  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(file_path) + ":" + SimpleItoa(parser.last_line()) +
+                   ":0: error: " + parser.error_str();
+      return false;
+    }
+  }
+  return parser.Finish();
+}
+
+}  // namespace
+
+bool ValidateObjCClassPrefix(const FileDescriptor* file, 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;
+  string expect_file_path;
+  if (!LoadExpectedPackagePrefixes(&expected_package_prefixes,
+                                   &expect_file_path, out_error)) {
+    // Any error, clear the entries that were read.
+    expected_package_prefixes.clear();
+  }
+
+  // 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 = "protoc:0: error: Expected 'option objc_class_prefix = \"" +
+                   package_match->second + "\";' 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 =
+          "protoc:0: 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 (" +
+          expect_file_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 ("
+         << expect_file_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..8574486
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -0,0 +1,175 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 {
+
+// 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
+};
+
+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);
+
+string BuildFlagsString(const vector<string>& strings);
+
+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, 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..2987f3d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -0,0 +1,163 @@
+// 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)
+    : RepeatedFieldGenerator(descriptor) {
+  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));
+
+  // 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);
+  if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
+      ((value_objc_type == OBJECTIVECTYPE_STRING) ||
+       (value_objc_type == OBJECTIVECTYPE_DATA) ||
+       (value_objc_type == OBJECTIVECTYPE_MESSAGE))) {
+    variables_["array_storage_type"] = "NSMutableDictionary";
+  } else {
+    string base_name = MapEntryTypeName(key_descriptor, true);
+    base_name += MapEntryTypeName(value_descriptor, false);
+    base_name += "Dictionary";
+    variables_["array_storage_type"] = "GPB" + base_name;
+  }
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  // Use the array_comment suport in RepeatedFieldGenerator to output what the
+  // values in the map are.
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->FindFieldByName("value");
+  ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
+  if ((value_objc_type == OBJECTIVECTYPE_MESSAGE) ||
+      (value_objc_type == OBJECTIVECTYPE_DATA) ||
+      (value_objc_type == OBJECTIVECTYPE_STRING) ||
+      (value_objc_type == OBJECTIVECTYPE_ENUM)) {
+    variables_["array_comment"] =
+        "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
+  } else {
+    variables_["array_comment"] = "";
+  }
+}
+
+void MapFieldGenerator::GenerateFieldDescriptionTypeSpecific(
+    io::Printer* printer) const {
+  // Relay it to the value generator to provide enum validator, message
+  // class, etc.
+  value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer);
+}
+
+}  // 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..173541f
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
@@ -0,0 +1,64 @@
+// 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);
+
+ public:
+  virtual void FinishInitialization(void);
+  virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
+
+ protected:
+  explicit MapFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~MapFieldGenerator();
+
+ 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..32671d4
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -0,0 +1,647 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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. Bools (1 byte)
+  //   2. Anything always 4 bytes - float, *32, enums
+  //   3. Anything that is always a pointer (they will be 8 bytes on 64 bit
+  //      builds and 4 bytes on 32bit builds.
+  //   4. Anything always 8 bytes - double, *64
+  //
+  // 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;
+
+    // 1 byte.
+    case FieldDescriptor::TYPE_BOOL:
+      return 1;
+  }
+
+  // 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)
+    : root_classname_(root_classname),
+      descriptor_(descriptor),
+      field_generators_(descriptor),
+      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));
+    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);
+      // If it is a the field is repeated, the type will be and *Array, and we
+      // don't need any forward decl.
+      if (fieldDescriptor->is_repeated()) {
+        continue;
+      }
+      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$@interface $classname$ : GPBMessage\n\n",
+      "classname", class_name_,
+      "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());
+
+    // TODO(thomasvl): Finish optimizing has bit. The current behavior is as
+    // follows:
+    // 1. objectivec_field.cc's SetCommonFieldVariables() defaults the has_index
+    //    to the field's index in the list of fields.
+    // 2. RepeatedFieldGenerator::RepeatedFieldGenerator() sets has_index to
+    //    GPBNoHasBit because repeated fields & map<> fields don't use the has
+    //    bit.
+    // 3. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
+    //    index that groups all the elements on of the oneof.
+    // So in has_storage, we need enough bits for the single fields that aren't
+    // in any oneof, and then one int32 for each oneof (to store the field
+    // number).  So we could save a little space by not using the field's index
+    // and instead make a second pass only assigning indexes for the fields
+    // that would need it.  The only savings would come when messages have over
+    // a multiple of 32 fields with some number being repeated or in oneofs to
+    // drop the count below that 32 multiple; so it hasn't seemed worth doing
+    // at the moment.
+    size_t num_has_bits = descriptor_->field_count();
+    size_t sizeof_has_storage = (num_has_bits + 31) / 32;
+    // 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);
+    // Add an int32 for each oneof to store which is set.
+    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");
+
+    bool has_oneofs = oneof_generators_.size();
+    if (has_oneofs) {
+      printer->Print(
+          "    static GPBMessageOneofDescription oneofs[] = {\n");
+      printer->Indent();
+      printer->Indent();
+      printer->Indent();
+      for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+           iter != oneof_generators_.end(); ++iter) {
+        (*iter)->GenerateDescription(printer);
+      }
+      printer->Outdent();
+      printer->Outdent();
+      printer->Outdent();
+      printer->Print(
+          "    };\n");
+    }
+
+    TextFormatDecodeData text_format_decode_data;
+    bool has_fields = descriptor_->field_count() > 0;
+    if (has_fields) {
+      // TODO(thomasvl): The plugin's FieldGenerator::GenerateFieldDescription()
+      // wraps the fieldOptions's value of this structure in an CPP gate so
+      // they can be compiled away; but that still results in a const char* in
+      // the structure for a NULL pointer for every message field.  If the
+      // fieldOptions are moved to a separate payload like the TextFormat extra
+      // data is, then it would shrink that static data shrinking the binaries
+      // a little more.
+      // TODO(thomasvl): proto3 syntax doens't need a defaultValue in the
+      // structure because primitive types are always zero.  If we add a second
+      // structure and a different initializer, we can avoid the wasted static
+      // storage for every field in a proto3 message.
+      printer->Print(
+          "    static GPBMessageFieldDescription fields[] = {\n");
+      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);
+        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");
+    }
+
+    bool has_enums = enum_generators_.size();
+    if (has_enums) {
+      printer->Print(
+          "    static GPBMessageEnumDescription enums[] = {\n");
+      printer->Indent();
+      printer->Indent();
+      printer->Indent();
+      for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
+           iter != enum_generators_.end(); ++iter) {
+        printer->Print("{ .enumDescriptorFunc = $name$_EnumDescriptor },\n",
+                       "name", (*iter)->name());
+      }
+      printer->Outdent();
+      printer->Outdent();
+      printer->Outdent();
+      printer->Print(
+          "    };\n");
+    }
+
+    bool has_extensions = sorted_extensions.size();
+    if (has_extensions) {
+      printer->Print(
+          "    static GPBExtensionRange ranges[] = {\n");
+      printer->Indent();
+      printer->Indent();
+      printer->Indent();
+      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->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";
+    vars["fields_count"] =
+        has_fields ? "sizeof(fields) / sizeof(GPBMessageFieldDescription)" : "0";
+    vars["oneofs"] = has_oneofs ? "oneofs" : "NULL";
+    vars["oneof_count"] =
+        has_oneofs ? "sizeof(oneofs) / sizeof(GPBMessageOneofDescription)" : "0";
+    vars["enums"] = has_enums ? "enums" : "NULL";
+    vars["enum_count"] =
+        has_enums ? "sizeof(enums) / sizeof(GPBMessageEnumDescription)" : "0";
+    vars["ranges"] = has_extensions ? "ranges" : "NULL";
+    vars["range_count"] =
+        has_extensions ? "sizeof(ranges) / sizeof(GPBExtensionRange)" : "0";
+    vars["wireformat"] =
+        descriptor_->options().message_set_wire_format() ? "YES" : "NO";
+
+    if (text_format_decode_data.num_entries() == 0) {
+      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"
+          "                                        oneofs:$oneofs$\n"
+          "                                    oneofCount:$oneof_count$\n"
+          "                                         enums:$enums$\n"
+          "                                     enumCount:$enum_count$\n"
+          "                                        ranges:$ranges$\n"
+          "                                    rangeCount:$range_count$\n"
+          "                                   storageSize:sizeof($classname$__storage_)\n"
+          "                                    wireFormat:$wireformat$];\n");
+    } else {
+      vars["extraTextFormatInfo"] = CEscape(text_format_decode_data.Data());
+      printer->Print(
+          vars,
+          "#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
+          "    const char *extraTextFormatInfo = NULL;\n"
+          "#else\n"
+          "    static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
+          "#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
+          "    GPBDescriptor *localDescriptor =\n"
+          "        [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
+          "                                     rootClass:[$rootclassname$ class]\n"
+          "                                          file:$rootclassname$_FileDescriptor()\n"
+          "                                        fields:$fields$\n"
+          "                                    fieldCount:$fields_count$\n"
+          "                                        oneofs:$oneofs$\n"
+          "                                    oneofCount:$oneof_count$\n"
+          "                                         enums:$enums$\n"
+          "                                     enumCount:$enum_count$\n"
+          "                                        ranges:$ranges$\n"
+          "                                    rangeCount:$range_count$\n"
+          "                                   storageSize:sizeof($classname$__storage_)\n"
+          "                                    wireFormat:$wireformat$\n"
+          "                           extraTextFormatInfo:extraTextFormatInfo];\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..06b536f
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.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_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);
+  ~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..f2ce4e5
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
@@ -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.
+
+#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)
+    : ObjCObjFieldGenerator(descriptor) {
+  SetMessageVariables(descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  // 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)
+    : RepeatedFieldGenerator(descriptor) {
+  SetMessageVariables(descriptor, &variables_);
+  variables_["array_storage_type"] = "NSMutableArray";
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+}  // 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..708ea56
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
@@ -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.
+
+#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);
+
+ protected:
+  explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+  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);
+
+ protected:
+  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~RepeatedMessageFieldGenerator();
+
+ 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..3cb8748
--- /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_,
+      "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, 0);\n"
+      "}\n");
+}
+
+void OneofGenerator::GenerateDescription(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "{\n"
+      "  .name = \"$name$\",\n"
+      "  .index = $index$,\n"
+      "},\n");
+}
+
+}  // 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..bcba82d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
@@ -0,0 +1,77 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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);
+  void GenerateDescription(io::Printer* printer);
+
+ 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..c185b66
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.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 <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;
+  }
+
+  // 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:
+      return "";  // Want NSArray
+  }
+
+  // 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)
+    : SingleFieldGenerator(descriptor) {
+  SetPrimitiveVariables(descriptor, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator(
+    const FieldDescriptor* descriptor)
+    : ObjCObjFieldGenerator(descriptor) {
+  SetPrimitiveVariables(descriptor, &variables_);
+  variables_["property_storage_attribute"] = "copy";
+}
+
+PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {}
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor)
+    : RepeatedFieldGenerator(descriptor) {
+  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";
+  }
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  if (IsPrimitiveType(descriptor_)) {
+    // No comment needed for primitive types.
+    variables_["array_comment"] = "";
+  }
+}
+
+}  // 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..9bb7934
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.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.
+
+#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);
+
+ protected:
+  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~PrimitiveFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+  explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~PrimitiveObjFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveObjFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~RepeatedPrimitiveFieldGenerator();
+  virtual void FinishInitialization(void);
+
+ 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 c50cdf5..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>
@@ -457,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;
@@ -488,9 +544,9 @@
       // 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. "
-                   << "Please use 'syntax = \"proto2\";' or "
-                   << "'syntax = \"proto3\";' to specify a syntax "
+      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";
     }
@@ -686,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);
@@ -733,6 +791,13 @@
     FieldDescriptorProto::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.");
+      }
     }
   }
 
@@ -929,6 +994,42 @@
   } 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,
@@ -947,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));
@@ -1094,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) {
@@ -1353,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,
@@ -1485,6 +1682,9 @@
   }
 
   DO(ParseEnumBlock(enum_type, enum_location, containing_file));
+
+  DO(ValidateEnum(enum_type));
+
   return true;
 }
 
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 7cb1678..2c561c2 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -323,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,
@@ -364,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,
@@ -407,7 +415,7 @@
                           Message* mutable_options);
 
   // Parse "required", "optional", or "repeated" and fill in "label"
-  // with the value. Returns true if shuch a label is consumed.
+  // with the value. Returns true if such a label is consumed.
   bool ParseLabel(FieldDescriptorProto::Label* label,
                   const FileDescriptorProto* containing_file);
 
@@ -431,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;"
@@ -486,6 +498,8 @@
   }
 
 
+  bool ValidateEnum(const EnumDescriptorProto* proto);
+
   // =================================================================
 
   io::Tokenizer* input_;
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 1684beb..1d623dd 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -229,6 +229,32 @@
 
 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"
@@ -426,6 +452,20 @@
 #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"
@@ -620,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"
@@ -715,19 +785,17 @@
     "            type_name:\"TestMessage\" extendee: \"Extendee1\" }");
 }
 
-TEST_F(ParseMessageTest, OptionalOptionalLabelProto3) {
+TEST_F(ParseMessageTest, OptionalLabelProto3) {
   ExpectParsesTo(
     "syntax = \"proto3\";\n"
     "message TestMessage {\n"
     "  int32 foo = 1;\n"
-    "  optional int32 bar = 2;\n"
     "}\n",
 
     "syntax: \"proto3\" "
     "message_type {"
     "  name: \"TestMessage\""
-    "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
-    "  field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 } }");
+    "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } }");
 }
 
 // ===================================================================
@@ -1072,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"
@@ -1086,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"
@@ -1230,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
 
@@ -1248,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) {
@@ -1716,6 +1862,8 @@
       "// 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"
@@ -1767,11 +1915,6 @@
       pool_.BuildFileCollectingErrors(parsed_desc, &collector);
   ASSERT_TRUE(descriptor != NULL);
 
-  DebugStringOptions debug_string_options;
-  debug_string_options.include_comments = true;
-  const string debug_string =
-      descriptor->DebugStringWithOptions(debug_string_options);
-
   // 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.
@@ -1782,6 +1925,7 @@
     "Package comment.",
     "Detached comment before TestMessage1.",
     "Message comment.",
+    "More detail in message comment.",
     "Detached comment before foo.",
     "Field comment",
     "Detached comment before NestedMessage.",
@@ -1796,11 +1940,28 @@
     "RPC comment",
   };
 
-  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.";
+  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) {
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index ad501ac..2bebf1f 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>
@@ -134,20 +135,34 @@
   CodeGeneratorResponse response;
   GeneratorResponseContext context(&response, parsed_files);
 
-  for (int i = 0; i < parsed_files.size(); i++) {
-    const FileDescriptor* file = parsed_files[i];
-
+  if (generator->HasGenerateAll()) {
     string error;
-    bool succeeded = generator->Generate(
-        file, request.parameter(), &context, &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(file->name() + ": " + error);
-      break;
+      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;
+      }
     }
   }
 
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index fed1726..a2da8ee 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>
@@ -172,14 +173,14 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest)
 }
@@ -300,12 +301,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;
       }
@@ -337,10 +341,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,
-    "google.protobuf.compiler.CodeGeneratorRequest.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);
   }
@@ -445,9 +449,9 @@
 
 void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const CodeGeneratorRequest* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorRequest*>(
-      &from);
+  const CodeGeneratorRequest* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -513,10 +517,10 @@
 // CodeGeneratorRequest
 
 // repeated string file_to_generate = 1;
- int CodeGeneratorRequest::file_to_generate_size() const {
+int CodeGeneratorRequest::file_to_generate_size() const {
   return file_to_generate_.size();
 }
- void CodeGeneratorRequest::clear_file_to_generate() {
+void CodeGeneratorRequest::clear_file_to_generate() {
   file_to_generate_.Clear();
 }
  const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
@@ -567,16 +571,16 @@
 }
 
 // optional string parameter = 2;
- bool CodeGeneratorRequest::has_parameter() const {
+bool CodeGeneratorRequest::has_parameter() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void CodeGeneratorRequest::set_has_parameter() {
+void CodeGeneratorRequest::set_has_parameter() {
   _has_bits_[0] |= 0x00000002u;
 }
- void CodeGeneratorRequest::clear_has_parameter() {
+void CodeGeneratorRequest::clear_has_parameter() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void CodeGeneratorRequest::clear_parameter() {
+void CodeGeneratorRequest::clear_parameter() {
   parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_parameter();
 }
@@ -620,47 +624,47 @@
 }
 
 // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
- int CodeGeneratorRequest::proto_file_size() const {
+int CodeGeneratorRequest::proto_file_size() const {
   return proto_file_.size();
 }
- void CodeGeneratorRequest::clear_proto_file() {
+void CodeGeneratorRequest::clear_proto_file() {
   proto_file_.Clear();
 }
- const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+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) {
+::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() {
+::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
   // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   return proto_file_.Add();
 }
- 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_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
 }
@@ -724,7 +728,7 @@
 }
 
 void CodeGeneratorResponse_File::Clear() {
-  if (_has_bits_[0 / 32] & 7) {
+  if (_has_bits_[0 / 32] & 7u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -910,7 +914,7 @@
 int CodeGeneratorResponse_File::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 7) {
+  if (_has_bits_[0 / 32] & 7u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -946,9 +950,9 @@
 
 void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const CodeGeneratorResponse_File* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse_File*>(
-      &from);
+  const CodeGeneratorResponse_File* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1018,13 +1022,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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse)
 }
@@ -1124,12 +1128,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;
       }
@@ -1242,9 +1249,9 @@
 
 void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const CodeGeneratorResponse* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse*>(
-      &from);
+  const CodeGeneratorResponse* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1307,16 +1314,16 @@
 // CodeGeneratorResponse_File
 
 // optional string name = 1;
- bool CodeGeneratorResponse_File::has_name() const {
+bool CodeGeneratorResponse_File::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void CodeGeneratorResponse_File::set_has_name() {
+void CodeGeneratorResponse_File::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void CodeGeneratorResponse_File::clear_has_name() {
+void CodeGeneratorResponse_File::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void CodeGeneratorResponse_File::clear_name() {
+void CodeGeneratorResponse_File::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -1360,16 +1367,16 @@
 }
 
 // optional string insertion_point = 2;
- bool CodeGeneratorResponse_File::has_insertion_point() const {
+bool CodeGeneratorResponse_File::has_insertion_point() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void CodeGeneratorResponse_File::set_has_insertion_point() {
+void CodeGeneratorResponse_File::set_has_insertion_point() {
   _has_bits_[0] |= 0x00000002u;
 }
- void CodeGeneratorResponse_File::clear_has_insertion_point() {
+void CodeGeneratorResponse_File::clear_has_insertion_point() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void CodeGeneratorResponse_File::clear_insertion_point() {
+void CodeGeneratorResponse_File::clear_insertion_point() {
   insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_insertion_point();
 }
@@ -1413,16 +1420,16 @@
 }
 
 // optional string content = 15;
- bool CodeGeneratorResponse_File::has_content() const {
+bool CodeGeneratorResponse_File::has_content() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void CodeGeneratorResponse_File::set_has_content() {
+void CodeGeneratorResponse_File::set_has_content() {
   _has_bits_[0] |= 0x00000004u;
 }
- void CodeGeneratorResponse_File::clear_has_content() {
+void CodeGeneratorResponse_File::clear_has_content() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void CodeGeneratorResponse_File::clear_content() {
+void CodeGeneratorResponse_File::clear_content() {
   content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_content();
 }
@@ -1470,16 +1477,16 @@
 // CodeGeneratorResponse
 
 // optional string error = 1;
- bool CodeGeneratorResponse::has_error() const {
+bool CodeGeneratorResponse::has_error() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void CodeGeneratorResponse::set_has_error() {
+void CodeGeneratorResponse::set_has_error() {
   _has_bits_[0] |= 0x00000001u;
 }
- void CodeGeneratorResponse::clear_has_error() {
+void CodeGeneratorResponse::clear_has_error() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void CodeGeneratorResponse::clear_error() {
+void CodeGeneratorResponse::clear_error() {
   error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_error();
 }
@@ -1523,34 +1530,34 @@
 }
 
 // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
- int CodeGeneratorResponse::file_size() const {
+int CodeGeneratorResponse::file_size() const {
   return file_.size();
 }
- void CodeGeneratorResponse::clear_file() {
+void CodeGeneratorResponse::clear_file() {
   file_.Clear();
 }
- const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+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) {
+::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() {
+::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
   // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
   return file_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
-CodeGeneratorResponse::file() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
-  return file_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+::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
 
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index ea48b8b..0a03e97 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -27,7 +27,7 @@
 #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 {
@@ -144,10 +144,10 @@
   const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
   ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
   ::google::protobuf::FileDescriptorProto* add_proto_file();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-      proto_file() const;
   ::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:
@@ -378,10 +378,10 @@
   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();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
-      file() const;
   ::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:
@@ -534,16 +534,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -784,18 +784,22 @@
   // @@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)
 
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 7b3b5fa..4d500f9 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -58,6 +58,7 @@
 #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>
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index 2ddac60..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 {
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
index a9b6837..9692f1b 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -47,7 +47,7 @@
 namespace ruby {
 
 // Forward decls.
-std::string IntToString(uint32 value);
+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);
@@ -64,7 +64,7 @@
     const google::protobuf::EnumDescriptor* en,
     google::protobuf::io::Printer* printer);
 
-std::string IntToString(uint32 value) {
+std::string IntToString(int32 value) {
   std::ostringstream os;
   os << value;
   return os.str();
@@ -85,17 +85,25 @@
 }
 
 std::string TypeName(const google::protobuf::FieldDescriptor* field) {
-  switch (field->cpp_type()) {
-    case FieldDescriptor::CPPTYPE_INT32: return "int32";
-    case FieldDescriptor::CPPTYPE_INT64: return "int64";
-    case FieldDescriptor::CPPTYPE_UINT32: return "uint32";
-    case FieldDescriptor::CPPTYPE_UINT64: return "uint64";
-    case FieldDescriptor::CPPTYPE_DOUBLE: return "double";
-    case FieldDescriptor::CPPTYPE_FLOAT: return "float";
-    case FieldDescriptor::CPPTYPE_BOOL: return "bool";
-    case FieldDescriptor::CPPTYPE_ENUM: return "enum";
-    case FieldDescriptor::CPPTYPE_STRING: return "string";
-    case FieldDescriptor::CPPTYPE_MESSAGE: return "message";
+  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 "";
   }
 }
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
index e35ca69..1b04cb3 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -45,10 +45,11 @@
 namespace ruby {
 namespace {
 
-string FindRubyTestDir() {
+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 + "/ruby/tests")) {
+  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 "
@@ -56,7 +57,10 @@
     }
     prefix += "/..";
   }
-  return prefix + "/ruby/tests";
+  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
@@ -67,7 +71,7 @@
 // extensions to the point where we can do this test in a more automated way.
 
 TEST(RubyGeneratorTest, GeneratorTest) {
-  string ruby_tests = FindRubyTestDir();
+  string ruby_tests = FindRubyTestDir("/ruby_generated_code.proto");
 
   google::protobuf::compiler::CommandLineInterface cli;
   cli.SetInputsAreProtoPathRelative(true);
@@ -78,11 +82,11 @@
   // Copy generated_code.proto to the temporary test directory.
   string test_input;
   GOOGLE_CHECK_OK(File::GetContents(
-      ruby_tests + "/generated_code.proto",
+      ruby_tests + "/ruby_generated_code.proto",
       &test_input,
       true));
   GOOGLE_CHECK_OK(File::SetContents(
-      TestTempDir() + "/generated_code.proto",
+      TestTempDir() + "/ruby_generated_code.proto",
       test_input,
       true));
 
@@ -93,7 +97,7 @@
     "protoc",
     ruby_out.c_str(),
     proto_path.c_str(),
-    "generated_code.proto",
+    "ruby_generated_code.proto",
   };
 
   EXPECT_EQ(0, cli.Run(4, argv));
@@ -101,12 +105,12 @@
   // Load the generated output and compare to the expected result.
   string output;
   GOOGLE_CHECK_OK(File::GetContents(
-      TestTempDir() + "/generated_code.rb",
+      TestTempDir() + "/ruby_generated_code.rb",
       &output,
       true));
   string expected_output;
   GOOGLE_CHECK_OK(File::GetContents(
-      ruby_tests + "/generated_code.rb",
+      ruby_tests + "/ruby_generated_code.rb",
       &expected_output,
       true));
   EXPECT_EQ(expected_output, output);
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 61ae438..a30ac30 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];
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index bfdacd9..78a3461 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,6 +57,8 @@
 #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>
@@ -150,7 +156,7 @@
 
 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;
@@ -554,7 +560,7 @@
   ~FileDescriptorTables();
 
   // Empty table, used with placeholder files.
-  static const FileDescriptorTables kEmpty;
+  inline static const FileDescriptorTables& GetEmptyInstance();
 
   // -----------------------------------------------------------------
   // Finding items.
@@ -659,7 +665,32 @@
 
 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));
@@ -1092,6 +1123,7 @@
   return generated_pool_;
 }
 
+
 DescriptorPool* DescriptorPool::internal_generated_pool() {
   InitGeneratedPoolOnce();
   return generated_pool_;
@@ -1518,6 +1550,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 {
@@ -1711,6 +1755,20 @@
   }
 }
 
+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_ &&
       source_code_info_ != &SourceCodeInfo::default_instance()) {
@@ -1741,15 +1799,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.
@@ -1796,6 +1883,10 @@
   }
 }
 
+void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
+  proto->set_json_name(json_name());
+}
+
 void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
   proto->set_name(name());
 }
@@ -1984,6 +2075,7 @@
   }
 
  private:
+
   bool have_source_loc_;
   SourceLocation source_loc_;
   DebugStringOptions options_;
@@ -2186,6 +2278,29 @@
   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);
 }
@@ -2278,8 +2393,12 @@
   }
 
   if (type() == TYPE_GROUP) {
-    message_type()->DebugString(depth, contents, debug_string_options,
-                                /* include_opening_clause */ false);
+    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");
   }
@@ -2308,12 +2427,16 @@
       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,
-                          debug_string_options);
+      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);
 }
 
@@ -2491,7 +2614,12 @@
 }
 
 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 {
@@ -2604,7 +2732,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.
@@ -2830,6 +2958,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);
@@ -2846,7 +2977,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.
   //
@@ -3430,7 +3562,7 @@
   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;
@@ -3640,6 +3772,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();
 }
 
@@ -3883,7 +4023,7 @@
 
 
   if (!unused_dependency_.empty()) {
-    LogUnusedDependency(result);
+    LogUnusedDependency(proto, result);
   }
 
   if (had_errors_) {
@@ -3920,6 +4060,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()) {
@@ -3931,7 +4082,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++) {
@@ -3945,11 +4123,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) {
@@ -3964,6 +4170,7 @@
   }
 }
 
+
 void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
                                               const Descriptor* parent,
                                               FieldDescriptor* result,
@@ -4000,6 +4207,14 @@
       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.
   result->type_  = static_cast<FieldDescriptor::Type>(
@@ -4061,8 +4276,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:
@@ -4234,6 +4449,7 @@
     AllocateOptions(proto.options(), result);
   }
 
+
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 }
@@ -4262,6 +4478,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) {
@@ -4503,6 +4732,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_;
@@ -4874,6 +5120,20 @@
   }
 }
 
+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) {
@@ -4901,6 +5161,25 @@
              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(
@@ -4933,6 +5212,11 @@
              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(
@@ -5146,6 +5430,14 @@
     // are added.
   }
 
+  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.");
+    }
+  }
+
   return true;
 }
 
@@ -5270,11 +5562,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;
 }
 
@@ -5423,7 +5723,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.
   }
@@ -5433,7 +5733,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(
@@ -5819,7 +6120,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();
 
@@ -5927,7 +6228,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;
@@ -5953,9 +6255,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 0e264f5..7e3a749 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 {
@@ -106,8 +115,17 @@
 
 // Defined in generated_message_reflection.h.
 namespace internal {
-  class GeneratedMessageReflection;
-}
+class GeneratedMessageReflection;
+}  // namespace internal
+
+// Defined in command_line_interface.cc
+namespace compiler {
+class CommandLineInterface;
+}  // namespace compiler
+
+namespace descriptor_unittest {
+class DescriptorTest;
+}  // namespace descriptor_unittest
 
 // NB, all indices are zero-based.
 struct SourceLocation {
@@ -131,10 +149,14 @@
   // 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)
-  {}
+      : include_comments(false),
+        elide_group_body(false),
+        elide_oneof_body(false) {}
 };
 
 // Describes a type of protocol message, or a particular group within a
@@ -294,6 +316,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
@@ -304,6 +356,12 @@
  private:
   typedef MessageOptions OptionsType;
 
+  // Allows tests to test CopyTo(proto, true).
+  friend class ::google::protobuf::descriptor_unittest::DescriptorTest;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(DescriptorProto* proto) const;
+
   // Internal version of DebugString; controls the level of indenting for
   // correct depth. Takes |options| to control debug-string options, and
   // |include_opening_clause| to indicate whether the "message ... " part of the
@@ -339,6 +397,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.
@@ -441,6 +503,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.
@@ -581,6 +644,9 @@
  private:
   typedef FieldOptions OptionsType;
 
+  // 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,
@@ -602,6 +668,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_;
@@ -818,7 +890,7 @@
   friend class FieldDescriptor;
   friend class EnumValueDescriptor;
   friend class FileDescriptor;
-  friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection;
+  friend class internal::GeneratedMessageReflection;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor);
 };
 
@@ -1159,6 +1231,9 @@
   // 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;
@@ -1290,6 +1365,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;
@@ -1515,7 +1591,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_;
@@ -1563,11 +1639,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*)
@@ -1607,7 +1690,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)
@@ -1622,14 +1705,14 @@
 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)
 
@@ -1643,7 +1726,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*)
@@ -1663,6 +1746,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;
 }
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 9556206..ff0cfcf 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
 
@@ -140,7 +151,7 @@
       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_),
@@ -149,6 +160,8 @@
     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_ =
     ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
@@ -177,8 +190,24 @@
       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_),
@@ -187,6 +216,7 @@
     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_ =
@@ -289,7 +319,7 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_),
       -1);
   FileOptions_descriptor_ = file->message_type(9);
-  static const int FileOptions_offsets_[14] = {
+  static const int FileOptions_offsets_[16] = {
     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_),
@@ -303,6 +333,8 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, deprecated_),
     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, javanano_use_deprecated_package_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_),
   };
   FileOptions_reflection_ =
@@ -337,9 +369,10 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_),
       -1);
   FieldOptions_descriptor_ = file->message_type(11);
-  static const int FieldOptions_offsets_[6] = {
+  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, weak_),
@@ -357,6 +390,7 @@
       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_),
@@ -493,6 +527,39 @@
       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 {
@@ -514,6 +581,8 @@
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DescriptorProto_ReservedRange_descriptor_, &DescriptorProto_ReservedRange::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       OneofDescriptorProto_descriptor_, &OneofDescriptorProto::default_instance());
@@ -547,6 +616,10 @@
       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
@@ -560,6 +633,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_;
@@ -594,6 +669,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() {
@@ -618,7 +697,7 @@
     "\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\022\016\n\006syntax\030\014 \001"
-    "(\t\"\344\003\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005"
+    "(\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"
@@ -629,102 +708,117 @@
     "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\032,\n\016ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003"
-    "end\030\002 \001(\005\"\251\005\n\024FieldDescriptorProto\022\014\n\004na"
-    "me\030\001 \001(\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162"
-    "+.google.protobuf.FieldDescriptorProto.L"
-    "abel\0228\n\004type\030\005 \001(\0162*.google.protobuf.Fie"
-    "ldDescriptorProto.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_index\030\t \001(\005\022.\n\007options\030\010 \001(\013"
-    "2\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\nTYP"
-    "E_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_G"
-    "ROUP\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_S"
-    "INT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LAB"
-    "EL_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LAB"
-    "EL_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n"
-    "\004name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004n"
-    "ame\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protob"
-    "uf.EnumValueDescriptorProto\022-\n\007options\030\003"
-    " \001(\0132\034.google.protobuf.EnumOptions\"l\n\030En"
-    "umValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006"
-    "number\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.p"
-    "rotobuf.EnumValueOptions\"\220\001\n\026ServiceDesc"
-    "riptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003("
-    "\0132&.google.protobuf.MethodDescriptorProt"
-    "o\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Ser"
-    "viceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n"
-    "\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013outpu"
-    "t_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.p"
-    "rotobuf.MethodOptions\022\037\n\020client_streamin"
-    "g\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010"
-    ":\005false\"\347\004\n\013FileOptions\022\024\n\014java_package\030"
-    "\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023j"
-    "ava_multiple_files\030\n \001(\010:\005false\022,\n\035java_"
-    "generate_equals_and_hash\030\024 \001(\010:\005false\022%\n"
-    "\026java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014"
-    "optimize_for\030\t \001(\0162).google.protobuf.Fil"
-    "eOptions.OptimizeMode:\005SPEED\022\022\n\ngo_packa"
-    "ge\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005f"
-    "alse\022$\n\025java_generic_services\030\021 \001(\010:\005fal"
-    "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031"
-    "\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_a"
-    "renas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030"
-    "$ \001(\t\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g"
-    "oogle.protobuf.UninterpretedOption\":\n\014Op"
-    "timizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014"
-    "LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOpt"
-    "ions\022&\n\027message_set_wire_format\030\001 \001(\010:\005f"
-    "alse\022.\n\037no_standard_descriptor_accessor\030"
-    "\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022"
-    "\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpreted_opti"
-    "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete"
-    "dOption*\t\010\350\007\020\200\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005c"
-    "type\030\001 \001(\0162#.google.protobuf.FieldOption"
-    "s.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"
-    "\023\n\004weak\030\n \001(\010:\005false\022C\n\024uninterpreted_op"
-    "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
-    "tedOption\"/\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\013EnumOp"
-    "tions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndeprecated"
-    "\030\003 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007"
-    " \003(\0132$.google.protobuf.UninterpretedOpti"
-    "on*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndep"
-    "recated\030\001 \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\"{\n\016ServiceOptions\022\031"
-    "\n\ndeprecated\030! \001(\010:\005false\022C\n\024uninterpret"
-    "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint"
-    "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptio"
-    "ns\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024uninter"
-    "preted_option\030\347\007 \003(\0132$.google.protobuf.U"
-    "ninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023Uninte"
-    "rpretedOption\022;\n\004name\030\002 \003(\0132-.google.pro"
-    "tobuf.UninterpretedOption.NamePart\022\030\n\020id"
-    "entifier_value\030\003 \001(\t\022\032\n\022positive_int_val"
-    "ue\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014"
-    "double_value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014"
-    "\022\027\n\017aggregate_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\"\325"
-    "\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003(\0132(.go"
-    "ogle.protobuf.SourceCodeInfo.Location\032\206\001"
-    "\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\020leading_comments\030\003 \001(\t\022\031\n\021trai"
-    "ling_comments\030\004 \001(\t\022!\n\031leading_detached_"
-    "comments\030\006 \003(\tB)\n\023com.google.protobufB\020D"
-    "escriptorProtosH\001", 4617);
+    "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\"\256\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\022+\n\037javana"
+    "no_use_deprecated_package\030& \001(\010B\002\030\001\022C\n\024u"
+    "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+    "obuf.UninterpretedOption\":\n\014OptimizeMode"
+    "\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTI"
+    "ME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027me"
+    "ssage_set_wire_format\030\001 \001(\010:\005false\022.\n\037no"
+    "_standard_descriptor_accessor\030\002 \001(\010:\005fal"
+    "se\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_ent"
+    "ry\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132"
+    "$.google.protobuf.UninterpretedOption*\t\010"
+    "\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\016"
+    "2#.google.protobuf.FieldOptions.CType:\006S"
+    "TRING\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\ndeprecate"
+    "d\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024u"
+    "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+    "obuf.UninterpretedOption\"/\n\005CType\022\n\n\006STR"
+    "ING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JST"
+    "ype\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\013a"
+    "llow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fa"
+    "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
+    "gle.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\ndeprecat"
+    "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030"
+    "\347\007 \003(\0132$.google.protobuf.UninterpretedOp"
+    "tion*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndepr"
+    "ecated\030! \001(\010:\005false\022C\n\024uninterpreted_opt"
+    "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret"
+    "edOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOpt"
+    "ion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Unin"
+    "terpretedOption.NamePart\022\030\n\020identifier_v"
+    "alue\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_val"
+    "ue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggreg"
+    "ate_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\"\325\001\n\016SourceC"
+    "odeInfo\022:\n\010location\030\001 \003(\0132(.google.proto"
+    "buf.SourceCodeInfo.Location\032\206\001\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\020"
+    "leading_comments\030\003 \001(\t\022\031\n\021trailing_comme"
+    "nts\030\004 \001(\t\022!\n\031leading_detached_comments\030\006"
+    " \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotation"
+    "\030\001 \003(\0132-.google.protobuf.GeneratedCodeIn"
+    "fo.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\020D"
+    "escriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032Go"
+    "ogle.Protobuf.Reflection", 5184);
   ::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();
@@ -742,10 +836,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();
@@ -763,6 +860,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);
 }
 
@@ -785,12 +884,12 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorSet)
 }
@@ -867,13 +966,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;
       }
@@ -958,9 +1059,9 @@
 
 void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FileDescriptorSet* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorSet*>(
-      &from);
+  const FileDescriptorSet* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorSet>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1017,40 +1118,40 @@
 // FileDescriptorSet
 
 // repeated .google.protobuf.FileDescriptorProto file = 1;
- int FileDescriptorSet::file_size() const {
+int FileDescriptorSet::file_size() const {
   return file_.size();
 }
- void FileDescriptorSet::clear_file() {
+void FileDescriptorSet::clear_file() {
   file_.Clear();
 }
- const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const {
+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) {
+::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() {
+::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() {
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
   return file_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-FileDescriptorSet::file() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
-  return file_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+::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;
@@ -1063,10 +1164,10 @@
 const int FileDescriptorProto::kOptionsFieldNumber;
 const int FileDescriptorProto::kSourceCodeInfoFieldNumber;
 const int FileDescriptorProto::kSyntaxFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileDescriptorProto::FileDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorProto)
 }
@@ -1136,7 +1237,7 @@
 }
 
 void FileDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 3) {
+  if (_has_bits_[0 / 32] & 3u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -1144,7 +1245,7 @@
       package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
-  if (_has_bits_[8 / 32] & 3584) {
+  if (_has_bits_[8 / 32] & 3584u) {
     if (has_options()) {
       if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
     }
@@ -1234,54 +1335,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;
       }
@@ -1414,10 +1524,10 @@
 
   // 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,
-    "google.protobuf.FileDescriptorProto.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);
   }
@@ -1598,7 +1708,7 @@
 int FileDescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 3) {
+  if (_has_bits_[0 / 32] & 3u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -1614,7 +1724,7 @@
     }
 
   }
-  if (_has_bits_[9 / 32] & 3584) {
+  if (_has_bits_[9 / 32] & 3584u) {
     // optional .google.protobuf.FileOptions options = 8;
     if (has_options()) {
       total_size += 1 +
@@ -1709,9 +1819,9 @@
 
 void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FileDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorProto*>(
-      &from);
+  const FileDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1813,16 +1923,16 @@
 // FileDescriptorProto
 
 // optional string name = 1;
- bool FileDescriptorProto::has_name() const {
+bool FileDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FileDescriptorProto::set_has_name() {
+void FileDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FileDescriptorProto::clear_has_name() {
+void FileDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FileDescriptorProto::clear_name() {
+void FileDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -1866,16 +1976,16 @@
 }
 
 // optional string package = 2;
- bool FileDescriptorProto::has_package() const {
+bool FileDescriptorProto::has_package() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FileDescriptorProto::set_has_package() {
+void FileDescriptorProto::set_has_package() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FileDescriptorProto::clear_has_package() {
+void FileDescriptorProto::clear_has_package() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FileDescriptorProto::clear_package() {
+void FileDescriptorProto::clear_package() {
   package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_package();
 }
@@ -1919,10 +2029,10 @@
 }
 
 // repeated string dependency = 3;
- int FileDescriptorProto::dependency_size() const {
+int FileDescriptorProto::dependency_size() const {
   return dependency_.size();
 }
- void FileDescriptorProto::clear_dependency() {
+void FileDescriptorProto::clear_dependency() {
   dependency_.Clear();
 }
  const ::std::string& FileDescriptorProto::dependency(int index) const {
@@ -1973,10 +2083,10 @@
 }
 
 // repeated int32 public_dependency = 10;
- int FileDescriptorProto::public_dependency_size() const {
+int FileDescriptorProto::public_dependency_size() const {
   return public_dependency_.size();
 }
- void FileDescriptorProto::clear_public_dependency() {
+void FileDescriptorProto::clear_public_dependency() {
   public_dependency_.Clear();
 }
  ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const {
@@ -2003,10 +2113,10 @@
 }
 
 // repeated int32 weak_dependency = 11;
- int FileDescriptorProto::weak_dependency_size() const {
+int FileDescriptorProto::weak_dependency_size() const {
   return weak_dependency_.size();
 }
- void FileDescriptorProto::clear_weak_dependency() {
+void FileDescriptorProto::clear_weak_dependency() {
   weak_dependency_.Clear();
 }
  ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const {
@@ -2033,144 +2143,144 @@
 }
 
 // repeated .google.protobuf.DescriptorProto message_type = 4;
- int FileDescriptorProto::message_type_size() const {
+int FileDescriptorProto::message_type_size() const {
   return message_type_.size();
 }
- void FileDescriptorProto::clear_message_type() {
+void FileDescriptorProto::clear_message_type() {
   message_type_.Clear();
 }
- const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+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) {
+::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() {
+::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() {
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
   return message_type_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-FileDescriptorProto::message_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
-  return message_type_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+::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 {
+int FileDescriptorProto::enum_type_size() const {
   return enum_type_.size();
 }
- void FileDescriptorProto::clear_enum_type() {
+void FileDescriptorProto::clear_enum_type() {
   enum_type_.Clear();
 }
- const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+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) {
+::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() {
+::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
   return enum_type_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-FileDescriptorProto::enum_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
-  return enum_type_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+::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 {
+int FileDescriptorProto::service_size() const {
   return service_.size();
 }
- void FileDescriptorProto::clear_service() {
+void FileDescriptorProto::clear_service() {
   service_.Clear();
 }
- const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+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) {
+::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() {
+::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() {
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
   return service_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
-FileDescriptorProto::service() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
-  return service_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
+::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 {
+int FileDescriptorProto::extension_size() const {
   return extension_.size();
 }
- void FileDescriptorProto::clear_extension() {
+void FileDescriptorProto::clear_extension() {
   extension_.Clear();
 }
- const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+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) {
+::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() {
+::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() {
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
   return extension_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-FileDescriptorProto::extension() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
-  return extension_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+::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 {
+bool FileDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000200u) != 0;
 }
- void FileDescriptorProto::set_has_options() {
+void FileDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000200u;
 }
- void FileDescriptorProto::clear_has_options() {
+void FileDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000200u;
 }
- void FileDescriptorProto::clear_options() {
+void FileDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
   clear_has_options();
 }
- const ::google::protobuf::FileOptions& FileDescriptorProto::options() const {
+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() {
+::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::FileOptions;
@@ -2178,13 +2288,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
   return options_;
 }
- ::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
+::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::FileOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) {
+void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -2196,24 +2306,24 @@
 }
 
 // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
- bool FileDescriptorProto::has_source_code_info() const {
+bool FileDescriptorProto::has_source_code_info() const {
   return (_has_bits_[0] & 0x00000400u) != 0;
 }
- void FileDescriptorProto::set_has_source_code_info() {
+void FileDescriptorProto::set_has_source_code_info() {
   _has_bits_[0] |= 0x00000400u;
 }
- void FileDescriptorProto::clear_has_source_code_info() {
+void FileDescriptorProto::clear_has_source_code_info() {
   _has_bits_[0] &= ~0x00000400u;
 }
- void FileDescriptorProto::clear_source_code_info() {
+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 {
+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() {
+::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;
@@ -2221,13 +2331,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
   return source_code_info_;
 }
- ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
+::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_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) {
+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) {
@@ -2239,16 +2349,16 @@
 }
 
 // optional string syntax = 12;
- bool FileDescriptorProto::has_syntax() const {
+bool FileDescriptorProto::has_syntax() const {
   return (_has_bits_[0] & 0x00000800u) != 0;
 }
- void FileDescriptorProto::set_has_syntax() {
+void FileDescriptorProto::set_has_syntax() {
   _has_bits_[0] |= 0x00000800u;
 }
- void FileDescriptorProto::clear_has_syntax() {
+void FileDescriptorProto::clear_has_syntax() {
   _has_bits_[0] &= ~0x00000800u;
 }
- void FileDescriptorProto::clear_syntax() {
+void FileDescriptorProto::clear_syntax() {
   syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_syntax();
 }
@@ -2295,13 +2405,13 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ExtensionRange)
 }
@@ -2484,7 +2594,7 @@
 int DescriptorProto_ExtensionRange::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 3) {
+  if (_has_bits_[0 / 32] & 3u) {
     // optional int32 start = 1;
     if (has_start()) {
       total_size += 1 +
@@ -2513,9 +2623,9 @@
 
 void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const DescriptorProto_ExtensionRange* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto_ExtensionRange*>(
-      &from);
+  const DescriptorProto_ExtensionRange* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ExtensionRange>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -2578,7 +2688,290 @@
 
 // -------------------------------------------------------------------
 
-#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() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<DescriptorProto_ReservedRange*>(16)->f)
+
+#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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DescriptorProto_ReservedRange* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ReservedRange>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) {
+  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;
@@ -2587,10 +2980,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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto)
 }
@@ -2653,7 +3048,7 @@
 }
 
 void DescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 129) {
+  if (_has_bits_[0 / 32] & 129u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -2667,6 +3062,8 @@
   enum_type_.Clear();
   extension_range_.Clear();
   oneof_decl_.Clear();
+  reserved_range_.Clear();
+  reserved_name_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   if (_internal_metadata_.have_unknown_fields()) {
     mutable_unknown_fields()->Clear();
@@ -2703,68 +3100,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;
       }
@@ -2786,12 +3194,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;
       }
@@ -2873,6 +3319,22 @@
       8, this->oneof_decl(i), output);
   }
 
+  // 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);
@@ -2943,6 +3405,23 @@
         8, this->oneof_decl(i), target);
   }
 
+  // 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);
@@ -2954,7 +3433,7 @@
 int DescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 129) {
+  if (_has_bits_[0 / 32] & 129u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -3018,6 +3497,21 @@
         this->oneof_decl(i));
   }
 
+  // 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(
@@ -3031,9 +3525,9 @@
 
 void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const DescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto*>(
-      &from);
+  const DescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -3049,6 +3543,8 @@
   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_has_name();
@@ -3100,6 +3596,8 @@
   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_);
@@ -3117,16 +3615,16 @@
 // DescriptorProto_ExtensionRange
 
 // optional int32 start = 1;
- bool DescriptorProto_ExtensionRange::has_start() const {
+bool DescriptorProto_ExtensionRange::has_start() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void DescriptorProto_ExtensionRange::set_has_start() {
+void DescriptorProto_ExtensionRange::set_has_start() {
   _has_bits_[0] |= 0x00000001u;
 }
- void DescriptorProto_ExtensionRange::clear_has_start() {
+void DescriptorProto_ExtensionRange::clear_has_start() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void DescriptorProto_ExtensionRange::clear_start() {
+void DescriptorProto_ExtensionRange::clear_start() {
   start_ = 0;
   clear_has_start();
 }
@@ -3141,16 +3639,16 @@
 }
 
 // optional int32 end = 2;
- bool DescriptorProto_ExtensionRange::has_end() const {
+bool DescriptorProto_ExtensionRange::has_end() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void DescriptorProto_ExtensionRange::set_has_end() {
+void DescriptorProto_ExtensionRange::set_has_end() {
   _has_bits_[0] |= 0x00000002u;
 }
- void DescriptorProto_ExtensionRange::clear_has_end() {
+void DescriptorProto_ExtensionRange::clear_has_end() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void DescriptorProto_ExtensionRange::clear_end() {
+void DescriptorProto_ExtensionRange::clear_end() {
   end_ = 0;
   clear_has_end();
 }
@@ -3166,19 +3664,71 @@
 
 // -------------------------------------------------------------------
 
+// 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 {
+bool DescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void DescriptorProto::set_has_name() {
+void DescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void DescriptorProto::clear_has_name() {
+void DescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void DescriptorProto::clear_name() {
+void DescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -3222,204 +3772,204 @@
 }
 
 // repeated .google.protobuf.FieldDescriptorProto field = 2;
- int DescriptorProto::field_size() const {
+int DescriptorProto::field_size() const {
   return field_.size();
 }
- void DescriptorProto::clear_field() {
+void DescriptorProto::clear_field() {
   field_.Clear();
 }
- const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const {
+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) {
+::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() {
+::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() {
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
   return field_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-DescriptorProto::field() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
-  return field_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+::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 {
+int DescriptorProto::extension_size() const {
   return extension_.size();
 }
- void DescriptorProto::clear_extension() {
+void DescriptorProto::clear_extension() {
   extension_.Clear();
 }
- const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+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) {
+::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() {
+::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() {
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
   return extension_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-DescriptorProto::extension() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
-  return extension_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+::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 {
+int DescriptorProto::nested_type_size() const {
   return nested_type_.size();
 }
- void DescriptorProto::clear_nested_type() {
+void DescriptorProto::clear_nested_type() {
   nested_type_.Clear();
 }
- const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const {
+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) {
+::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() {
+::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() {
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
   return nested_type_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-DescriptorProto::nested_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
-  return nested_type_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+::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 {
+int DescriptorProto::enum_type_size() const {
   return enum_type_.size();
 }
- void DescriptorProto::clear_enum_type() {
+void DescriptorProto::clear_enum_type() {
   enum_type_.Clear();
 }
- const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+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) {
+::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() {
+::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() {
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
   return enum_type_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-DescriptorProto::enum_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
-  return enum_type_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+::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 {
+int DescriptorProto::extension_range_size() const {
   return extension_range_.size();
 }
- void DescriptorProto::clear_extension_range() {
+void DescriptorProto::clear_extension_range() {
   extension_range_.Clear();
 }
- const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+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) {
+::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() {
+::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
   return extension_range_.Add();
 }
- 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_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
+::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 {
+int DescriptorProto::oneof_decl_size() const {
   return oneof_decl_.size();
 }
- void DescriptorProto::clear_oneof_decl() {
+void DescriptorProto::clear_oneof_decl() {
   oneof_decl_.Clear();
 }
- const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
+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) {
+::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() {
+::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl() {
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
   return oneof_decl_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
-DescriptorProto::oneof_decl() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
-  return oneof_decl_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
+::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 {
+bool DescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000080u) != 0;
 }
- void DescriptorProto::set_has_options() {
+void DescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000080u;
 }
- void DescriptorProto::clear_has_options() {
+void DescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000080u;
 }
- void DescriptorProto::clear_options() {
+void DescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
   clear_has_options();
 }
- const ::google::protobuf::MessageOptions& DescriptorProto::options() const {
+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() {
+::google::protobuf::MessageOptions* DescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::MessageOptions;
@@ -3427,13 +3977,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
   return options_;
 }
- ::google::protobuf::MessageOptions* DescriptorProto::release_options() {
+::google::protobuf::MessageOptions* DescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::MessageOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) {
+void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -3444,6 +3994,90 @@
   // @@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() {
+  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
 
 // ===================================================================
@@ -3478,7 +4112,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;
@@ -3500,7 +4134,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_;
@@ -3516,15 +4150,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;
@@ -3533,11 +4167,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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldDescriptorProto)
 }
@@ -3565,6 +4200,7 @@
   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_));
 }
@@ -3579,6 +4215,7 @@
   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_;
   }
@@ -3610,7 +4247,7 @@
 }
 
 void FieldDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 255) {
+  if (_has_bits_[0 / 32] & 255u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -3628,8 +4265,13 @@
     }
     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_));
   if (_internal_metadata_.have_unknown_fields()) {
@@ -3793,6 +4435,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;
       }
@@ -3890,6 +4549,16 @@
     ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output);
   }
 
+  // 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);
@@ -3973,6 +4642,17 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target);
   }
 
+  // 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);
@@ -3984,7 +4664,7 @@
 int FieldDescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 255) {
+  if (_has_bits_[0 / 32] & 255u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -4040,13 +4720,22 @@
     }
 
   }
-  // optional .google.protobuf.FieldOptions options = 8;
-  if (has_options()) {
-    total_size += 1 +
-      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-        *this->options_);
-  }
+  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_);
+    }
+
+  }
   if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -4060,9 +4749,9 @@
 
 void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FieldDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldDescriptorProto*>(
-      &from);
+  const FieldDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -4103,6 +4792,10 @@
     }
   }
   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());
     }
@@ -4145,6 +4838,7 @@
   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_);
@@ -4163,16 +4857,16 @@
 // FieldDescriptorProto
 
 // optional string name = 1;
- bool FieldDescriptorProto::has_name() const {
+bool FieldDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FieldDescriptorProto::set_has_name() {
+void FieldDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FieldDescriptorProto::clear_has_name() {
+void FieldDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FieldDescriptorProto::clear_name() {
+void FieldDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -4216,16 +4910,16 @@
 }
 
 // optional int32 number = 3;
- bool FieldDescriptorProto::has_number() const {
+bool FieldDescriptorProto::has_number() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FieldDescriptorProto::set_has_number() {
+void FieldDescriptorProto::set_has_number() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FieldDescriptorProto::clear_has_number() {
+void FieldDescriptorProto::clear_has_number() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FieldDescriptorProto::clear_number() {
+void FieldDescriptorProto::clear_number() {
   number_ = 0;
   clear_has_number();
 }
@@ -4240,16 +4934,16 @@
 }
 
 // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
- bool FieldDescriptorProto::has_label() const {
+bool FieldDescriptorProto::has_label() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void FieldDescriptorProto::set_has_label() {
+void FieldDescriptorProto::set_has_label() {
   _has_bits_[0] |= 0x00000004u;
 }
- void FieldDescriptorProto::clear_has_label() {
+void FieldDescriptorProto::clear_has_label() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void FieldDescriptorProto::clear_label() {
+void FieldDescriptorProto::clear_label() {
   label_ = 1;
   clear_has_label();
 }
@@ -4265,16 +4959,16 @@
 }
 
 // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
- bool FieldDescriptorProto::has_type() const {
+bool FieldDescriptorProto::has_type() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void FieldDescriptorProto::set_has_type() {
+void FieldDescriptorProto::set_has_type() {
   _has_bits_[0] |= 0x00000008u;
 }
- void FieldDescriptorProto::clear_has_type() {
+void FieldDescriptorProto::clear_has_type() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void FieldDescriptorProto::clear_type() {
+void FieldDescriptorProto::clear_type() {
   type_ = 1;
   clear_has_type();
 }
@@ -4290,16 +4984,16 @@
 }
 
 // optional string type_name = 6;
- bool FieldDescriptorProto::has_type_name() const {
+bool FieldDescriptorProto::has_type_name() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void FieldDescriptorProto::set_has_type_name() {
+void FieldDescriptorProto::set_has_type_name() {
   _has_bits_[0] |= 0x00000010u;
 }
- void FieldDescriptorProto::clear_has_type_name() {
+void FieldDescriptorProto::clear_has_type_name() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void FieldDescriptorProto::clear_type_name() {
+void FieldDescriptorProto::clear_type_name() {
   type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_type_name();
 }
@@ -4343,16 +5037,16 @@
 }
 
 // optional string extendee = 2;
- bool FieldDescriptorProto::has_extendee() const {
+bool FieldDescriptorProto::has_extendee() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void FieldDescriptorProto::set_has_extendee() {
+void FieldDescriptorProto::set_has_extendee() {
   _has_bits_[0] |= 0x00000020u;
 }
- void FieldDescriptorProto::clear_has_extendee() {
+void FieldDescriptorProto::clear_has_extendee() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void FieldDescriptorProto::clear_extendee() {
+void FieldDescriptorProto::clear_extendee() {
   extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_extendee();
 }
@@ -4396,16 +5090,16 @@
 }
 
 // optional string default_value = 7;
- bool FieldDescriptorProto::has_default_value() const {
+bool FieldDescriptorProto::has_default_value() const {
   return (_has_bits_[0] & 0x00000040u) != 0;
 }
- void FieldDescriptorProto::set_has_default_value() {
+void FieldDescriptorProto::set_has_default_value() {
   _has_bits_[0] |= 0x00000040u;
 }
- void FieldDescriptorProto::clear_has_default_value() {
+void FieldDescriptorProto::clear_has_default_value() {
   _has_bits_[0] &= ~0x00000040u;
 }
- void FieldDescriptorProto::clear_default_value() {
+void FieldDescriptorProto::clear_default_value() {
   default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_default_value();
 }
@@ -4449,16 +5143,16 @@
 }
 
 // optional int32 oneof_index = 9;
- bool FieldDescriptorProto::has_oneof_index() const {
+bool FieldDescriptorProto::has_oneof_index() const {
   return (_has_bits_[0] & 0x00000080u) != 0;
 }
- void FieldDescriptorProto::set_has_oneof_index() {
+void FieldDescriptorProto::set_has_oneof_index() {
   _has_bits_[0] |= 0x00000080u;
 }
- void FieldDescriptorProto::clear_has_oneof_index() {
+void FieldDescriptorProto::clear_has_oneof_index() {
   _has_bits_[0] &= ~0x00000080u;
 }
- void FieldDescriptorProto::clear_oneof_index() {
+void FieldDescriptorProto::clear_oneof_index() {
   oneof_index_ = 0;
   clear_has_oneof_index();
 }
@@ -4472,25 +5166,78 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
 }
 
-// optional .google.protobuf.FieldOptions options = 8;
- bool FieldDescriptorProto::has_options() const {
+// optional string json_name = 10;
+bool FieldDescriptorProto::has_json_name() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
- void FieldDescriptorProto::set_has_options() {
+void FieldDescriptorProto::set_has_json_name() {
   _has_bits_[0] |= 0x00000100u;
 }
- void FieldDescriptorProto::clear_has_options() {
+void FieldDescriptorProto::clear_has_json_name() {
   _has_bits_[0] &= ~0x00000100u;
 }
- void FieldDescriptorProto::clear_options() {
+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() {
+  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 {
+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() {
+::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::FieldOptions;
@@ -4498,13 +5245,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
   return options_;
 }
- ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() {
+::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::FieldOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) {
+void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -4519,12 +5266,12 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.OneofDescriptorProto)
 }
@@ -4706,9 +5453,9 @@
 
 void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const OneofDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const OneofDescriptorProto*>(
-      &from);
+  const OneofDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const OneofDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -4769,16 +5516,16 @@
 // OneofDescriptorProto
 
 // optional string name = 1;
- bool OneofDescriptorProto::has_name() const {
+bool OneofDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void OneofDescriptorProto::set_has_name() {
+void OneofDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void OneofDescriptorProto::clear_has_name() {
+void OneofDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void OneofDescriptorProto::clear_name() {
+void OneofDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -4825,14 +5572,14 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumDescriptorProto)
 }
@@ -4895,7 +5642,7 @@
 }
 
 void EnumDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 5) {
+  if (_has_bits_[0 / 32] & 5u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -4940,12 +5687,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;
       }
@@ -5056,7 +5806,7 @@
 int EnumDescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 5) {
+  if (_has_bits_[0 / 32] & 5u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -5093,9 +5843,9 @@
 
 void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumDescriptorProto*>(
-      &from);
+  const EnumDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -5166,16 +5916,16 @@
 // EnumDescriptorProto
 
 // optional string name = 1;
- bool EnumDescriptorProto::has_name() const {
+bool EnumDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumDescriptorProto::set_has_name() {
+void EnumDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumDescriptorProto::clear_has_name() {
+void EnumDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumDescriptorProto::clear_name() {
+void EnumDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -5219,54 +5969,54 @@
 }
 
 // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- int EnumDescriptorProto::value_size() const {
+int EnumDescriptorProto::value_size() const {
   return value_.size();
 }
- void EnumDescriptorProto::clear_value() {
+void EnumDescriptorProto::clear_value() {
   value_.Clear();
 }
- const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+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) {
+::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() {
+::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
   // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
   return value_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
-EnumDescriptorProto::value() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
-  return value_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
+::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 {
+bool EnumDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void EnumDescriptorProto::set_has_options() {
+void EnumDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000004u;
 }
- void EnumDescriptorProto::clear_has_options() {
+void EnumDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void EnumDescriptorProto::clear_options() {
+void EnumDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
   clear_has_options();
 }
- const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const {
+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() {
+::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::EnumOptions;
@@ -5274,13 +6024,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
   return options_;
 }
- ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
+::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::EnumOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) {
+void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -5295,14 +6045,14 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValueDescriptorProto)
 }
@@ -5366,7 +6116,7 @@
 }
 
 void EnumValueDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 7) {
+  if (_has_bits_[0 / 32] & 7u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -5525,7 +6275,7 @@
 int EnumValueDescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 7) {
+  if (_has_bits_[0 / 32] & 7u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -5561,9 +6311,9 @@
 
 void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumValueDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueDescriptorProto*>(
-      &from);
+  const EnumValueDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -5635,16 +6385,16 @@
 // EnumValueDescriptorProto
 
 // optional string name = 1;
- bool EnumValueDescriptorProto::has_name() const {
+bool EnumValueDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumValueDescriptorProto::set_has_name() {
+void EnumValueDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumValueDescriptorProto::clear_has_name() {
+void EnumValueDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumValueDescriptorProto::clear_name() {
+void EnumValueDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -5688,16 +6438,16 @@
 }
 
 // optional int32 number = 2;
- bool EnumValueDescriptorProto::has_number() const {
+bool EnumValueDescriptorProto::has_number() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void EnumValueDescriptorProto::set_has_number() {
+void EnumValueDescriptorProto::set_has_number() {
   _has_bits_[0] |= 0x00000002u;
 }
- void EnumValueDescriptorProto::clear_has_number() {
+void EnumValueDescriptorProto::clear_has_number() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void EnumValueDescriptorProto::clear_number() {
+void EnumValueDescriptorProto::clear_number() {
   number_ = 0;
   clear_has_number();
 }
@@ -5712,24 +6462,24 @@
 }
 
 // optional .google.protobuf.EnumValueOptions options = 3;
- bool EnumValueDescriptorProto::has_options() const {
+bool EnumValueDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void EnumValueDescriptorProto::set_has_options() {
+void EnumValueDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000004u;
 }
- void EnumValueDescriptorProto::clear_has_options() {
+void EnumValueDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void EnumValueDescriptorProto::clear_options() {
+void EnumValueDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear();
   clear_has_options();
 }
- const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const {
+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() {
+::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::EnumValueOptions;
@@ -5737,13 +6487,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
   return options_;
 }
- ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() {
+::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::EnumValueOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) {
+void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -5758,14 +6508,14 @@
 
 // ===================================================================
 
-#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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ServiceDescriptorProto)
 }
@@ -5828,7 +6578,7 @@
 }
 
 void ServiceDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 5) {
+  if (_has_bits_[0 / 32] & 5u) {
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -5873,12 +6623,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;
       }
@@ -5989,7 +6742,7 @@
 int ServiceDescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 5) {
+  if (_has_bits_[0 / 32] & 5u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -6026,9 +6779,9 @@
 
 void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const ServiceDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ServiceDescriptorProto*>(
-      &from);
+  const ServiceDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ServiceDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -6099,16 +6852,16 @@
 // ServiceDescriptorProto
 
 // optional string name = 1;
- bool ServiceDescriptorProto::has_name() const {
+bool ServiceDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void ServiceDescriptorProto::set_has_name() {
+void ServiceDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void ServiceDescriptorProto::clear_has_name() {
+void ServiceDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void ServiceDescriptorProto::clear_name() {
+void ServiceDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -6152,54 +6905,54 @@
 }
 
 // repeated .google.protobuf.MethodDescriptorProto method = 2;
- int ServiceDescriptorProto::method_size() const {
+int ServiceDescriptorProto::method_size() const {
   return method_.size();
 }
- void ServiceDescriptorProto::clear_method() {
+void ServiceDescriptorProto::clear_method() {
   method_.Clear();
 }
- const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+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) {
+::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() {
+::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
   // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
   return method_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
-ServiceDescriptorProto::method() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
-  return method_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
+::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 {
+bool ServiceDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void ServiceDescriptorProto::set_has_options() {
+void ServiceDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000004u;
 }
- void ServiceDescriptorProto::clear_has_options() {
+void ServiceDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void ServiceDescriptorProto::clear_options() {
+void ServiceDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
   clear_has_options();
 }
- const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const {
+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() {
+::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::ServiceOptions;
@@ -6207,13 +6960,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
   return options_;
 }
- ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() {
+::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::ServiceOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) {
+void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -6228,17 +6981,17 @@
 
 // ===================================================================
 
-#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;
 const int MethodDescriptorProto::kClientStreamingFieldNumber;
 const int MethodDescriptorProto::kServerStreamingFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MethodDescriptorProto::MethodDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MethodDescriptorProto)
 }
@@ -6315,7 +7068,7 @@
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
-  if (_has_bits_[0 / 32] & 63) {
+  if (_has_bits_[0 / 32] & 63u) {
     ZR_(client_streaming_, server_streaming_);
     if (has_name()) {
       name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
@@ -6585,7 +7338,7 @@
 int MethodDescriptorProto::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 63) {
+  if (_has_bits_[0 / 32] & 63u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -6638,9 +7391,9 @@
 
 void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const MethodDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MethodDescriptorProto*>(
-      &from);
+  const MethodDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MethodDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -6726,16 +7479,16 @@
 // MethodDescriptorProto
 
 // optional string name = 1;
- bool MethodDescriptorProto::has_name() const {
+bool MethodDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void MethodDescriptorProto::set_has_name() {
+void MethodDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void MethodDescriptorProto::clear_has_name() {
+void MethodDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void MethodDescriptorProto::clear_name() {
+void MethodDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -6779,16 +7532,16 @@
 }
 
 // optional string input_type = 2;
- bool MethodDescriptorProto::has_input_type() const {
+bool MethodDescriptorProto::has_input_type() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void MethodDescriptorProto::set_has_input_type() {
+void MethodDescriptorProto::set_has_input_type() {
   _has_bits_[0] |= 0x00000002u;
 }
- void MethodDescriptorProto::clear_has_input_type() {
+void MethodDescriptorProto::clear_has_input_type() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void MethodDescriptorProto::clear_input_type() {
+void MethodDescriptorProto::clear_input_type() {
   input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_input_type();
 }
@@ -6832,16 +7585,16 @@
 }
 
 // optional string output_type = 3;
- bool MethodDescriptorProto::has_output_type() const {
+bool MethodDescriptorProto::has_output_type() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void MethodDescriptorProto::set_has_output_type() {
+void MethodDescriptorProto::set_has_output_type() {
   _has_bits_[0] |= 0x00000004u;
 }
- void MethodDescriptorProto::clear_has_output_type() {
+void MethodDescriptorProto::clear_has_output_type() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void MethodDescriptorProto::clear_output_type() {
+void MethodDescriptorProto::clear_output_type() {
   output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_output_type();
 }
@@ -6885,24 +7638,24 @@
 }
 
 // optional .google.protobuf.MethodOptions options = 4;
- bool MethodDescriptorProto::has_options() const {
+bool MethodDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void MethodDescriptorProto::set_has_options() {
+void MethodDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000008u;
 }
- void MethodDescriptorProto::clear_has_options() {
+void MethodDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void MethodDescriptorProto::clear_options() {
+void MethodDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
   clear_has_options();
 }
- const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const {
+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() {
+::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() {
   set_has_options();
   if (options_ == NULL) {
     options_ = new ::google::protobuf::MethodOptions;
@@ -6910,13 +7663,13 @@
   // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
   return options_;
 }
- ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() {
+::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() {
   clear_has_options();
   ::google::protobuf::MethodOptions* temp = options_;
   options_ = NULL;
   return temp;
 }
- void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) {
+void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) {
   delete options_;
   options_ = options;
   if (options) {
@@ -6928,16 +7681,16 @@
 }
 
 // optional bool client_streaming = 5 [default = false];
- bool MethodDescriptorProto::has_client_streaming() const {
+bool MethodDescriptorProto::has_client_streaming() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void MethodDescriptorProto::set_has_client_streaming() {
+void MethodDescriptorProto::set_has_client_streaming() {
   _has_bits_[0] |= 0x00000010u;
 }
- void MethodDescriptorProto::clear_has_client_streaming() {
+void MethodDescriptorProto::clear_has_client_streaming() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void MethodDescriptorProto::clear_client_streaming() {
+void MethodDescriptorProto::clear_client_streaming() {
   client_streaming_ = false;
   clear_has_client_streaming();
 }
@@ -6952,16 +7705,16 @@
 }
 
 // optional bool server_streaming = 6 [default = false];
- bool MethodDescriptorProto::has_server_streaming() const {
+bool MethodDescriptorProto::has_server_streaming() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void MethodDescriptorProto::set_has_server_streaming() {
+void MethodDescriptorProto::set_has_server_streaming() {
   _has_bits_[0] |= 0x00000020u;
 }
- void MethodDescriptorProto::clear_has_server_streaming() {
+void MethodDescriptorProto::clear_has_server_streaming() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void MethodDescriptorProto::clear_server_streaming() {
+void MethodDescriptorProto::clear_server_streaming() {
   server_streaming_ = false;
   clear_has_server_streaming();
 }
@@ -6994,15 +7747,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;
@@ -7016,11 +7769,13 @@
 const int FileOptions::kDeprecatedFieldNumber;
 const int FileOptions::kCcEnableArenasFieldNumber;
 const int FileOptions::kObjcClassPrefixFieldNumber;
+const int FileOptions::kCsharpNamespaceFieldNumber;
+const int FileOptions::kJavananoUseDeprecatedPackageFieldNumber;
 const int FileOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileOptions::FileOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileOptions)
 }
@@ -7052,6 +7807,8 @@
   deprecated_ = false;
   cc_enable_arenas_ = false;
   objc_class_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  csharp_namespace_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  javanano_use_deprecated_package_ = false;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -7065,6 +7822,7 @@
   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_) {
   }
 }
@@ -7104,7 +7862,7 @@
            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()) {
       java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
@@ -7117,11 +7875,14 @@
       go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
-  if (_has_bits_[8 / 32] & 7936) {
-    ZR_(java_generic_services_, cc_enable_arenas_);
+  if (_has_bits_[8 / 32] & 32512u) {
+    ZR_(java_generic_services_, javanano_use_deprecated_package_);
     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 ZR_HELPER_
@@ -7347,6 +8108,38 @@
         } 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;
+        }
+        if (input->ExpectTag(304)) goto parse_javanano_use_deprecated_package;
+        break;
+      }
+
+      // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+      case 38: {
+        if (tag == 304) {
+         parse_javanano_use_deprecated_package:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &javanano_use_deprecated_package_)));
+          set_has_javanano_use_deprecated_package();
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
         break;
       }
@@ -7355,12 +8148,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;
       }
@@ -7481,6 +8277,21 @@
       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);
+  }
+
+  // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+  if (has_javanano_use_deprecated_package()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(38, this->javanano_use_deprecated_package(), output);
+  }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
@@ -7591,6 +8402,22 @@
         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);
+  }
+
+  // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+  if (has_javanano_use_deprecated_package()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(38, this->javanano_use_deprecated_package(), target);
+  }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
@@ -7613,7 +8440,7 @@
 int FileOptions::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 255) {
+  if (_has_bits_[0 / 32] & 255u) {
     // optional string java_package = 1;
     if (has_java_package()) {
       total_size += 1 +
@@ -7662,7 +8489,7 @@
     }
 
   }
-  if (_has_bits_[8 / 32] & 7936) {
+  if (_has_bits_[8 / 32] & 32512u) {
     // optional bool java_generic_services = 17 [default = false];
     if (has_java_generic_services()) {
       total_size += 2 + 1;
@@ -7690,6 +8517,18 @@
           this->objc_class_prefix());
     }
 
+    // optional string csharp_namespace = 37;
+    if (has_csharp_namespace()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->csharp_namespace());
+    }
+
+    // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+    if (has_javanano_use_deprecated_package()) {
+      total_size += 2 + 1;
+    }
+
   }
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   total_size += 2 * this->uninterpreted_option_size();
@@ -7714,9 +8553,9 @@
 
 void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FileOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileOptions*>(
-      &from);
+  const FileOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -7773,6 +8612,13 @@
       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_);
+    }
+    if (from.has_javanano_use_deprecated_package()) {
+      set_javanano_use_deprecated_package(from.javanano_use_deprecated_package());
+    }
   }
   _extensions_.MergeFrom(from._extensions_);
   if (from._internal_metadata_.have_unknown_fields()) {
@@ -7817,6 +8663,8 @@
   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_);
+  std::swap(javanano_use_deprecated_package_, other->javanano_use_deprecated_package_);
   uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
   std::swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -7836,16 +8684,16 @@
 // FileOptions
 
 // optional string java_package = 1;
- bool FileOptions::has_java_package() const {
+bool FileOptions::has_java_package() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FileOptions::set_has_java_package() {
+void FileOptions::set_has_java_package() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FileOptions::clear_has_java_package() {
+void FileOptions::clear_has_java_package() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FileOptions::clear_java_package() {
+void FileOptions::clear_java_package() {
   java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_java_package();
 }
@@ -7889,16 +8737,16 @@
 }
 
 // optional string java_outer_classname = 8;
- bool FileOptions::has_java_outer_classname() const {
+bool FileOptions::has_java_outer_classname() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FileOptions::set_has_java_outer_classname() {
+void FileOptions::set_has_java_outer_classname() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FileOptions::clear_has_java_outer_classname() {
+void FileOptions::clear_has_java_outer_classname() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FileOptions::clear_java_outer_classname() {
+void FileOptions::clear_java_outer_classname() {
   java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_java_outer_classname();
 }
@@ -7942,16 +8790,16 @@
 }
 
 // optional bool java_multiple_files = 10 [default = false];
- bool FileOptions::has_java_multiple_files() const {
+bool FileOptions::has_java_multiple_files() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void FileOptions::set_has_java_multiple_files() {
+void FileOptions::set_has_java_multiple_files() {
   _has_bits_[0] |= 0x00000004u;
 }
- void FileOptions::clear_has_java_multiple_files() {
+void FileOptions::clear_has_java_multiple_files() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void FileOptions::clear_java_multiple_files() {
+void FileOptions::clear_java_multiple_files() {
   java_multiple_files_ = false;
   clear_has_java_multiple_files();
 }
@@ -7966,16 +8814,16 @@
 }
 
 // optional bool java_generate_equals_and_hash = 20 [default = false];
- bool FileOptions::has_java_generate_equals_and_hash() const {
+bool FileOptions::has_java_generate_equals_and_hash() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void FileOptions::set_has_java_generate_equals_and_hash() {
+void FileOptions::set_has_java_generate_equals_and_hash() {
   _has_bits_[0] |= 0x00000008u;
 }
- void FileOptions::clear_has_java_generate_equals_and_hash() {
+void FileOptions::clear_has_java_generate_equals_and_hash() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void FileOptions::clear_java_generate_equals_and_hash() {
+void FileOptions::clear_java_generate_equals_and_hash() {
   java_generate_equals_and_hash_ = false;
   clear_has_java_generate_equals_and_hash();
 }
@@ -7990,16 +8838,16 @@
 }
 
 // optional bool java_string_check_utf8 = 27 [default = false];
- bool FileOptions::has_java_string_check_utf8() const {
+bool FileOptions::has_java_string_check_utf8() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void FileOptions::set_has_java_string_check_utf8() {
+void FileOptions::set_has_java_string_check_utf8() {
   _has_bits_[0] |= 0x00000010u;
 }
- void FileOptions::clear_has_java_string_check_utf8() {
+void FileOptions::clear_has_java_string_check_utf8() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void FileOptions::clear_java_string_check_utf8() {
+void FileOptions::clear_java_string_check_utf8() {
   java_string_check_utf8_ = false;
   clear_has_java_string_check_utf8();
 }
@@ -8014,16 +8862,16 @@
 }
 
 // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
- bool FileOptions::has_optimize_for() const {
+bool FileOptions::has_optimize_for() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void FileOptions::set_has_optimize_for() {
+void FileOptions::set_has_optimize_for() {
   _has_bits_[0] |= 0x00000020u;
 }
- void FileOptions::clear_has_optimize_for() {
+void FileOptions::clear_has_optimize_for() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void FileOptions::clear_optimize_for() {
+void FileOptions::clear_optimize_for() {
   optimize_for_ = 1;
   clear_has_optimize_for();
 }
@@ -8039,16 +8887,16 @@
 }
 
 // optional string go_package = 11;
- bool FileOptions::has_go_package() const {
+bool FileOptions::has_go_package() const {
   return (_has_bits_[0] & 0x00000040u) != 0;
 }
- void FileOptions::set_has_go_package() {
+void FileOptions::set_has_go_package() {
   _has_bits_[0] |= 0x00000040u;
 }
- void FileOptions::clear_has_go_package() {
+void FileOptions::clear_has_go_package() {
   _has_bits_[0] &= ~0x00000040u;
 }
- void FileOptions::clear_go_package() {
+void FileOptions::clear_go_package() {
   go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_go_package();
 }
@@ -8092,16 +8940,16 @@
 }
 
 // optional bool cc_generic_services = 16 [default = false];
- bool FileOptions::has_cc_generic_services() const {
+bool FileOptions::has_cc_generic_services() const {
   return (_has_bits_[0] & 0x00000080u) != 0;
 }
- void FileOptions::set_has_cc_generic_services() {
+void FileOptions::set_has_cc_generic_services() {
   _has_bits_[0] |= 0x00000080u;
 }
- void FileOptions::clear_has_cc_generic_services() {
+void FileOptions::clear_has_cc_generic_services() {
   _has_bits_[0] &= ~0x00000080u;
 }
- void FileOptions::clear_cc_generic_services() {
+void FileOptions::clear_cc_generic_services() {
   cc_generic_services_ = false;
   clear_has_cc_generic_services();
 }
@@ -8116,16 +8964,16 @@
 }
 
 // optional bool java_generic_services = 17 [default = false];
- bool FileOptions::has_java_generic_services() const {
+bool FileOptions::has_java_generic_services() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
- void FileOptions::set_has_java_generic_services() {
+void FileOptions::set_has_java_generic_services() {
   _has_bits_[0] |= 0x00000100u;
 }
- void FileOptions::clear_has_java_generic_services() {
+void FileOptions::clear_has_java_generic_services() {
   _has_bits_[0] &= ~0x00000100u;
 }
- void FileOptions::clear_java_generic_services() {
+void FileOptions::clear_java_generic_services() {
   java_generic_services_ = false;
   clear_has_java_generic_services();
 }
@@ -8140,16 +8988,16 @@
 }
 
 // optional bool py_generic_services = 18 [default = false];
- bool FileOptions::has_py_generic_services() const {
+bool FileOptions::has_py_generic_services() const {
   return (_has_bits_[0] & 0x00000200u) != 0;
 }
- void FileOptions::set_has_py_generic_services() {
+void FileOptions::set_has_py_generic_services() {
   _has_bits_[0] |= 0x00000200u;
 }
- void FileOptions::clear_has_py_generic_services() {
+void FileOptions::clear_has_py_generic_services() {
   _has_bits_[0] &= ~0x00000200u;
 }
- void FileOptions::clear_py_generic_services() {
+void FileOptions::clear_py_generic_services() {
   py_generic_services_ = false;
   clear_has_py_generic_services();
 }
@@ -8164,16 +9012,16 @@
 }
 
 // optional bool deprecated = 23 [default = false];
- bool FileOptions::has_deprecated() const {
+bool FileOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000400u) != 0;
 }
- void FileOptions::set_has_deprecated() {
+void FileOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000400u;
 }
- void FileOptions::clear_has_deprecated() {
+void FileOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000400u;
 }
- void FileOptions::clear_deprecated() {
+void FileOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -8188,16 +9036,16 @@
 }
 
 // optional bool cc_enable_arenas = 31 [default = false];
- bool FileOptions::has_cc_enable_arenas() const {
+bool FileOptions::has_cc_enable_arenas() const {
   return (_has_bits_[0] & 0x00000800u) != 0;
 }
- void FileOptions::set_has_cc_enable_arenas() {
+void FileOptions::set_has_cc_enable_arenas() {
   _has_bits_[0] |= 0x00000800u;
 }
- void FileOptions::clear_has_cc_enable_arenas() {
+void FileOptions::clear_has_cc_enable_arenas() {
   _has_bits_[0] &= ~0x00000800u;
 }
- void FileOptions::clear_cc_enable_arenas() {
+void FileOptions::clear_cc_enable_arenas() {
   cc_enable_arenas_ = false;
   clear_has_cc_enable_arenas();
 }
@@ -8212,16 +9060,16 @@
 }
 
 // optional string objc_class_prefix = 36;
- bool FileOptions::has_objc_class_prefix() const {
+bool FileOptions::has_objc_class_prefix() const {
   return (_has_bits_[0] & 0x00001000u) != 0;
 }
- void FileOptions::set_has_objc_class_prefix() {
+void FileOptions::set_has_objc_class_prefix() {
   _has_bits_[0] |= 0x00001000u;
 }
- void FileOptions::clear_has_objc_class_prefix() {
+void FileOptions::clear_has_objc_class_prefix() {
   _has_bits_[0] &= ~0x00001000u;
 }
- void FileOptions::clear_objc_class_prefix() {
+void FileOptions::clear_objc_class_prefix() {
   objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_objc_class_prefix();
 }
@@ -8264,50 +9112,127 @@
   // @@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() {
+  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)
+}
+
+// optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+bool FileOptions::has_javanano_use_deprecated_package() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void FileOptions::set_has_javanano_use_deprecated_package() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void FileOptions::clear_has_javanano_use_deprecated_package() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void FileOptions::clear_javanano_use_deprecated_package() {
+  javanano_use_deprecated_package_ = false;
+  clear_has_javanano_use_deprecated_package();
+}
+ bool FileOptions::javanano_use_deprecated_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.javanano_use_deprecated_package)
+  return javanano_use_deprecated_package_;
+}
+ 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)
+}
+
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int FileOptions::uninterpreted_option_size() const {
+int FileOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void FileOptions::clear_uninterpreted_option() {
+void FileOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-FileOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MessageOptions)
 }
@@ -8462,12 +9387,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;
       }
@@ -8584,7 +9512,7 @@
 int MessageOptions::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 15) {
+  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;
@@ -8629,9 +9557,9 @@
 
 void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const MessageOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageOptions*>(
-      &from);
+  const MessageOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -8709,16 +9637,16 @@
 // MessageOptions
 
 // optional bool message_set_wire_format = 1 [default = false];
- bool MessageOptions::has_message_set_wire_format() const {
+bool MessageOptions::has_message_set_wire_format() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void MessageOptions::set_has_message_set_wire_format() {
+void MessageOptions::set_has_message_set_wire_format() {
   _has_bits_[0] |= 0x00000001u;
 }
- void MessageOptions::clear_has_message_set_wire_format() {
+void MessageOptions::clear_has_message_set_wire_format() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void MessageOptions::clear_message_set_wire_format() {
+void MessageOptions::clear_message_set_wire_format() {
   message_set_wire_format_ = false;
   clear_has_message_set_wire_format();
 }
@@ -8733,16 +9661,16 @@
 }
 
 // optional bool no_standard_descriptor_accessor = 2 [default = false];
- bool MessageOptions::has_no_standard_descriptor_accessor() const {
+bool MessageOptions::has_no_standard_descriptor_accessor() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void MessageOptions::set_has_no_standard_descriptor_accessor() {
+void MessageOptions::set_has_no_standard_descriptor_accessor() {
   _has_bits_[0] |= 0x00000002u;
 }
- void MessageOptions::clear_has_no_standard_descriptor_accessor() {
+void MessageOptions::clear_has_no_standard_descriptor_accessor() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void MessageOptions::clear_no_standard_descriptor_accessor() {
+void MessageOptions::clear_no_standard_descriptor_accessor() {
   no_standard_descriptor_accessor_ = false;
   clear_has_no_standard_descriptor_accessor();
 }
@@ -8757,16 +9685,16 @@
 }
 
 // optional bool deprecated = 3 [default = false];
- bool MessageOptions::has_deprecated() const {
+bool MessageOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void MessageOptions::set_has_deprecated() {
+void MessageOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000004u;
 }
- void MessageOptions::clear_has_deprecated() {
+void MessageOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void MessageOptions::clear_deprecated() {
+void MessageOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -8781,16 +9709,16 @@
 }
 
 // optional bool map_entry = 7;
- bool MessageOptions::has_map_entry() const {
+bool MessageOptions::has_map_entry() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void MessageOptions::set_has_map_entry() {
+void MessageOptions::set_has_map_entry() {
   _has_bits_[0] |= 0x00000008u;
 }
- void MessageOptions::clear_has_map_entry() {
+void MessageOptions::clear_has_map_entry() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void MessageOptions::clear_map_entry() {
+void MessageOptions::clear_map_entry() {
   map_entry_ = false;
   clear_has_map_entry();
 }
@@ -8805,34 +9733,34 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int MessageOptions::uninterpreted_option_size() const {
+int MessageOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void MessageOptions::clear_uninterpreted_option() {
+void MessageOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-MessageOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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
 
@@ -8853,25 +9781,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::kWeakFieldNumber;
 const int FieldOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FieldOptions::FieldOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldOptions)
 }
@@ -8891,6 +9843,7 @@
   _cached_size_ = 0;
   ctype_ = 0;
   packed_ = false;
+  jstype_ = 0;
   lazy_ = false;
   deprecated_ = false;
   weak_ = false;
@@ -8942,8 +9895,9 @@
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
-  if (_has_bits_[0 / 32] & 31) {
-    ZR_(ctype_, weak_);
+  if (_has_bits_[0 / 32] & 63u) {
+    ZR_(ctype_, jstype_);
+    ZR_(packed_, weak_);
   }
 
 #undef ZR_HELPER_
@@ -9026,6 +9980,26 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(48)) goto parse_jstype;
+        break;
+      }
+
+      // 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;
+        }
         if (input->ExpectTag(80)) goto parse_weak;
         break;
       }
@@ -9049,12 +10023,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;
       }
@@ -9110,6 +10087,12 @@
     ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), 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];
   if (has_weak()) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->weak(), output);
@@ -9156,6 +10139,12 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), 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];
   if (has_weak()) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target);
@@ -9183,7 +10172,7 @@
 int FieldOptions::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 31) {
+  if (_has_bits_[0 / 32] & 63u) {
     // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
     if (has_ctype()) {
       total_size += 1 +
@@ -9195,6 +10184,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;
@@ -9234,9 +10229,9 @@
 
 void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FieldOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldOptions*>(
-      &from);
+  const FieldOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -9254,6 +10249,9 @@
     if (from.has_packed()) {
       set_packed(from.packed());
     }
+    if (from.has_jstype()) {
+      set_jstype(from.jstype());
+    }
     if (from.has_lazy()) {
       set_lazy(from.lazy());
     }
@@ -9296,6 +10294,7 @@
 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_);
@@ -9318,16 +10317,16 @@
 // FieldOptions
 
 // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
- bool FieldOptions::has_ctype() const {
+bool FieldOptions::has_ctype() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FieldOptions::set_has_ctype() {
+void FieldOptions::set_has_ctype() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FieldOptions::clear_has_ctype() {
+void FieldOptions::clear_has_ctype() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FieldOptions::clear_ctype() {
+void FieldOptions::clear_ctype() {
   ctype_ = 0;
   clear_has_ctype();
 }
@@ -9343,16 +10342,16 @@
 }
 
 // optional bool packed = 2;
- bool FieldOptions::has_packed() const {
+bool FieldOptions::has_packed() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FieldOptions::set_has_packed() {
+void FieldOptions::set_has_packed() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FieldOptions::clear_has_packed() {
+void FieldOptions::clear_has_packed() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FieldOptions::clear_packed() {
+void FieldOptions::clear_packed() {
   packed_ = false;
   clear_has_packed();
 }
@@ -9366,17 +10365,42 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
 }
 
-// optional bool lazy = 5 [default = false];
- bool FieldOptions::has_lazy() const {
+// 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_lazy() {
+void FieldOptions::set_has_jstype() {
   _has_bits_[0] |= 0x00000004u;
 }
- void FieldOptions::clear_has_lazy() {
+void FieldOptions::clear_has_jstype() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void FieldOptions::clear_lazy() {
+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();
 }
@@ -9391,16 +10415,16 @@
 }
 
 // optional bool deprecated = 3 [default = false];
- bool FieldOptions::has_deprecated() const {
-  return (_has_bits_[0] & 0x00000008u) != 0;
+bool FieldOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void FieldOptions::set_has_deprecated() {
-  _has_bits_[0] |= 0x00000008u;
+void FieldOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000010u;
 }
- void FieldOptions::clear_has_deprecated() {
-  _has_bits_[0] &= ~0x00000008u;
+void FieldOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000010u;
 }
- void FieldOptions::clear_deprecated() {
+void FieldOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -9415,16 +10439,16 @@
 }
 
 // optional bool weak = 10 [default = false];
- bool FieldOptions::has_weak() const {
-  return (_has_bits_[0] & 0x00000010u) != 0;
+bool FieldOptions::has_weak() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void FieldOptions::set_has_weak() {
-  _has_bits_[0] |= 0x00000010u;
+void FieldOptions::set_has_weak() {
+  _has_bits_[0] |= 0x00000020u;
 }
- void FieldOptions::clear_has_weak() {
-  _has_bits_[0] &= ~0x00000010u;
+void FieldOptions::clear_has_weak() {
+  _has_bits_[0] &= ~0x00000020u;
 }
- void FieldOptions::clear_weak() {
+void FieldOptions::clear_weak() {
   weak_ = false;
   clear_has_weak();
 }
@@ -9439,47 +10463,47 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int FieldOptions::uninterpreted_option_size() const {
+int FieldOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void FieldOptions::clear_uninterpreted_option() {
+void FieldOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-FieldOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumOptions)
 }
@@ -9602,12 +10626,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;
       }
@@ -9704,7 +10731,7 @@
 int EnumOptions::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 3) {
+  if (_has_bits_[0 / 32] & 3u) {
     // optional bool allow_alias = 2;
     if (has_allow_alias()) {
       total_size += 1 + 1;
@@ -9739,9 +10766,9 @@
 
 void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumOptions*>(
-      &from);
+  const EnumOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -9811,16 +10838,16 @@
 // EnumOptions
 
 // optional bool allow_alias = 2;
- bool EnumOptions::has_allow_alias() const {
+bool EnumOptions::has_allow_alias() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumOptions::set_has_allow_alias() {
+void EnumOptions::set_has_allow_alias() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumOptions::clear_has_allow_alias() {
+void EnumOptions::clear_has_allow_alias() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumOptions::clear_allow_alias() {
+void EnumOptions::clear_allow_alias() {
   allow_alias_ = false;
   clear_has_allow_alias();
 }
@@ -9835,16 +10862,16 @@
 }
 
 // optional bool deprecated = 3 [default = false];
- bool EnumOptions::has_deprecated() const {
+bool EnumOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void EnumOptions::set_has_deprecated() {
+void EnumOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000002u;
 }
- void EnumOptions::clear_has_deprecated() {
+void EnumOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void EnumOptions::clear_deprecated() {
+void EnumOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -9859,46 +10886,46 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int EnumOptions::uninterpreted_option_size() const {
+int EnumOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void EnumOptions::clear_uninterpreted_option() {
+void EnumOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-EnumOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValueOptions)
 }
@@ -9993,12 +11020,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;
       }
@@ -10113,9 +11143,9 @@
 
 void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumValueOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueOptions*>(
-      &from);
+  const EnumValueOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -10181,16 +11211,16 @@
 // EnumValueOptions
 
 // optional bool deprecated = 1 [default = false];
- bool EnumValueOptions::has_deprecated() const {
+bool EnumValueOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumValueOptions::set_has_deprecated() {
+void EnumValueOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumValueOptions::clear_has_deprecated() {
+void EnumValueOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumValueOptions::clear_deprecated() {
+void EnumValueOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -10205,46 +11235,46 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int EnumValueOptions::uninterpreted_option_size() const {
+int EnumValueOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void EnumValueOptions::clear_uninterpreted_option() {
+void EnumValueOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-EnumValueOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ServiceOptions)
 }
@@ -10339,12 +11369,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;
       }
@@ -10459,9 +11492,9 @@
 
 void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const ServiceOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ServiceOptions*>(
-      &from);
+  const ServiceOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ServiceOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -10527,16 +11560,16 @@
 // ServiceOptions
 
 // optional bool deprecated = 33 [default = false];
- bool ServiceOptions::has_deprecated() const {
+bool ServiceOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void ServiceOptions::set_has_deprecated() {
+void ServiceOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000001u;
 }
- void ServiceOptions::clear_has_deprecated() {
+void ServiceOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void ServiceOptions::clear_deprecated() {
+void ServiceOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -10551,46 +11584,46 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int ServiceOptions::uninterpreted_option_size() const {
+int ServiceOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void ServiceOptions::clear_uninterpreted_option() {
+void ServiceOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-ServiceOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MethodOptions)
 }
@@ -10685,12 +11718,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;
       }
@@ -10805,9 +11841,9 @@
 
 void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const MethodOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MethodOptions*>(
-      &from);
+  const MethodOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MethodOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -10873,16 +11909,16 @@
 // MethodOptions
 
 // optional bool deprecated = 33 [default = false];
- bool MethodOptions::has_deprecated() const {
+bool MethodOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void MethodOptions::set_has_deprecated() {
+void MethodOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000001u;
 }
- void MethodOptions::clear_has_deprecated() {
+void MethodOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void MethodOptions::clear_deprecated() {
+void MethodOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -10897,46 +11933,46 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int MethodOptions::uninterpreted_option_size() const {
+int MethodOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void MethodOptions::clear_uninterpreted_option() {
+void MethodOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
- const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() {
   // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-MethodOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+::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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption.NamePart)
 }
@@ -10997,7 +12033,7 @@
 }
 
 void UninterpretedOption_NamePart::Clear() {
-  if (_has_bits_[0 / 32] & 3) {
+  if (_has_bits_[0 / 32] & 3u) {
     if (has_name_part()) {
       name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -11169,9 +12205,9 @@
 
 void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const UninterpretedOption_NamePart* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption_NamePart*>(
-      &from);
+  const UninterpretedOption_NamePart* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption_NamePart>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -11236,7 +12272,7 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UninterpretedOption::kNameFieldNumber;
 const int UninterpretedOption::kIdentifierValueFieldNumber;
 const int UninterpretedOption::kPositiveIntValueFieldNumber;
@@ -11244,10 +12280,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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption)
 }
@@ -11322,7 +12358,7 @@
            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()) {
       identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
@@ -11358,13 +12394,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;
       }
@@ -11605,7 +12643,7 @@
 int UninterpretedOption::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[1 / 32] & 126) {
+  if (_has_bits_[1 / 32] & 126u) {
     // optional string identifier_value = 3;
     if (has_identifier_value()) {
       total_size += 1 +
@@ -11668,9 +12706,9 @@
 
 void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const UninterpretedOption* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption*>(
-      &from);
+  const UninterpretedOption* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -11756,16 +12794,16 @@
 // UninterpretedOption_NamePart
 
 // required string name_part = 1;
- bool UninterpretedOption_NamePart::has_name_part() const {
+bool UninterpretedOption_NamePart::has_name_part() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void UninterpretedOption_NamePart::set_has_name_part() {
+void UninterpretedOption_NamePart::set_has_name_part() {
   _has_bits_[0] |= 0x00000001u;
 }
- void UninterpretedOption_NamePart::clear_has_name_part() {
+void UninterpretedOption_NamePart::clear_has_name_part() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void UninterpretedOption_NamePart::clear_name_part() {
+void UninterpretedOption_NamePart::clear_name_part() {
   name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name_part();
 }
@@ -11809,16 +12847,16 @@
 }
 
 // required bool is_extension = 2;
- bool UninterpretedOption_NamePart::has_is_extension() const {
+bool UninterpretedOption_NamePart::has_is_extension() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void UninterpretedOption_NamePart::set_has_is_extension() {
+void UninterpretedOption_NamePart::set_has_is_extension() {
   _has_bits_[0] |= 0x00000002u;
 }
- void UninterpretedOption_NamePart::clear_has_is_extension() {
+void UninterpretedOption_NamePart::clear_has_is_extension() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void UninterpretedOption_NamePart::clear_is_extension() {
+void UninterpretedOption_NamePart::clear_is_extension() {
   is_extension_ = false;
   clear_has_is_extension();
 }
@@ -11837,46 +12875,46 @@
 // UninterpretedOption
 
 // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- int UninterpretedOption::name_size() const {
+int UninterpretedOption::name_size() const {
   return name_.size();
 }
- void UninterpretedOption::clear_name() {
+void UninterpretedOption::clear_name() {
   name_.Clear();
 }
- const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
+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) {
+::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() {
+::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() {
   // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
   return name_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
-UninterpretedOption::name() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
-  return name_;
-}
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
+::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 {
+bool UninterpretedOption::has_identifier_value() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void UninterpretedOption::set_has_identifier_value() {
+void UninterpretedOption::set_has_identifier_value() {
   _has_bits_[0] |= 0x00000002u;
 }
- void UninterpretedOption::clear_has_identifier_value() {
+void UninterpretedOption::clear_has_identifier_value() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void UninterpretedOption::clear_identifier_value() {
+void UninterpretedOption::clear_identifier_value() {
   identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_identifier_value();
 }
@@ -11920,16 +12958,16 @@
 }
 
 // optional uint64 positive_int_value = 4;
- bool UninterpretedOption::has_positive_int_value() const {
+bool UninterpretedOption::has_positive_int_value() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void UninterpretedOption::set_has_positive_int_value() {
+void UninterpretedOption::set_has_positive_int_value() {
   _has_bits_[0] |= 0x00000004u;
 }
- void UninterpretedOption::clear_has_positive_int_value() {
+void UninterpretedOption::clear_has_positive_int_value() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void UninterpretedOption::clear_positive_int_value() {
+void UninterpretedOption::clear_positive_int_value() {
   positive_int_value_ = GOOGLE_ULONGLONG(0);
   clear_has_positive_int_value();
 }
@@ -11944,16 +12982,16 @@
 }
 
 // optional int64 negative_int_value = 5;
- bool UninterpretedOption::has_negative_int_value() const {
+bool UninterpretedOption::has_negative_int_value() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void UninterpretedOption::set_has_negative_int_value() {
+void UninterpretedOption::set_has_negative_int_value() {
   _has_bits_[0] |= 0x00000008u;
 }
- void UninterpretedOption::clear_has_negative_int_value() {
+void UninterpretedOption::clear_has_negative_int_value() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void UninterpretedOption::clear_negative_int_value() {
+void UninterpretedOption::clear_negative_int_value() {
   negative_int_value_ = GOOGLE_LONGLONG(0);
   clear_has_negative_int_value();
 }
@@ -11968,16 +13006,16 @@
 }
 
 // optional double double_value = 6;
- bool UninterpretedOption::has_double_value() const {
+bool UninterpretedOption::has_double_value() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void UninterpretedOption::set_has_double_value() {
+void UninterpretedOption::set_has_double_value() {
   _has_bits_[0] |= 0x00000010u;
 }
- void UninterpretedOption::clear_has_double_value() {
+void UninterpretedOption::clear_has_double_value() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void UninterpretedOption::clear_double_value() {
+void UninterpretedOption::clear_double_value() {
   double_value_ = 0;
   clear_has_double_value();
 }
@@ -11992,16 +13030,16 @@
 }
 
 // optional bytes string_value = 7;
- bool UninterpretedOption::has_string_value() const {
+bool UninterpretedOption::has_string_value() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void UninterpretedOption::set_has_string_value() {
+void UninterpretedOption::set_has_string_value() {
   _has_bits_[0] |= 0x00000020u;
 }
- void UninterpretedOption::clear_has_string_value() {
+void UninterpretedOption::clear_has_string_value() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void UninterpretedOption::clear_string_value() {
+void UninterpretedOption::clear_string_value() {
   string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_string_value();
 }
@@ -12045,16 +13083,16 @@
 }
 
 // optional string aggregate_value = 8;
- bool UninterpretedOption::has_aggregate_value() const {
+bool UninterpretedOption::has_aggregate_value() const {
   return (_has_bits_[0] & 0x00000040u) != 0;
 }
- void UninterpretedOption::set_has_aggregate_value() {
+void UninterpretedOption::set_has_aggregate_value() {
   _has_bits_[0] |= 0x00000040u;
 }
- void UninterpretedOption::clear_has_aggregate_value() {
+void UninterpretedOption::clear_has_aggregate_value() {
   _has_bits_[0] &= ~0x00000040u;
 }
- void UninterpretedOption::clear_aggregate_value() {
+void UninterpretedOption::clear_aggregate_value() {
   aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_aggregate_value();
 }
@@ -12101,16 +13139,16 @@
 
 // ===================================================================
 
-#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;
 const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 SourceCodeInfo_Location::SourceCodeInfo_Location()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo.Location)
 }
@@ -12172,7 +13210,7 @@
 }
 
 void SourceCodeInfo_Location::Clear() {
-  if (_has_bits_[0 / 32] & 12) {
+  if (_has_bits_[0 / 32] & 12u) {
     if (has_leading_comments()) {
       leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
@@ -12354,10 +13392,10 @@
 
   // 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::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);
   }
@@ -12443,7 +13481,7 @@
 int SourceCodeInfo_Location::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[2 / 32] & 12) {
+  if (_has_bits_[2 / 32] & 12u) {
     // optional string leading_comments = 3;
     if (has_leading_comments()) {
       total_size += 1 +
@@ -12513,9 +13551,9 @@
 
 void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const SourceCodeInfo_Location* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo_Location*>(
-      &from);
+  const SourceCodeInfo_Location* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo_Location>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -12586,12 +13624,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() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo)
 }
@@ -12668,13 +13706,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;
       }
@@ -12759,9 +13799,9 @@
 
 void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const SourceCodeInfo* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo*>(
-      &from);
+  const SourceCodeInfo* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -12817,10 +13857,10 @@
 // SourceCodeInfo_Location
 
 // repeated int32 path = 1 [packed = true];
- int SourceCodeInfo_Location::path_size() const {
+int SourceCodeInfo_Location::path_size() const {
   return path_.size();
 }
- void SourceCodeInfo_Location::clear_path() {
+void SourceCodeInfo_Location::clear_path() {
   path_.Clear();
 }
  ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const {
@@ -12847,10 +13887,10 @@
 }
 
 // repeated int32 span = 2 [packed = true];
- int SourceCodeInfo_Location::span_size() const {
+int SourceCodeInfo_Location::span_size() const {
   return span_.size();
 }
- void SourceCodeInfo_Location::clear_span() {
+void SourceCodeInfo_Location::clear_span() {
   span_.Clear();
 }
  ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const {
@@ -12877,16 +13917,16 @@
 }
 
 // optional string leading_comments = 3;
- bool SourceCodeInfo_Location::has_leading_comments() const {
+bool SourceCodeInfo_Location::has_leading_comments() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void SourceCodeInfo_Location::set_has_leading_comments() {
+void SourceCodeInfo_Location::set_has_leading_comments() {
   _has_bits_[0] |= 0x00000004u;
 }
- void SourceCodeInfo_Location::clear_has_leading_comments() {
+void SourceCodeInfo_Location::clear_has_leading_comments() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void SourceCodeInfo_Location::clear_leading_comments() {
+void SourceCodeInfo_Location::clear_leading_comments() {
   leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_leading_comments();
 }
@@ -12930,16 +13970,16 @@
 }
 
 // optional string trailing_comments = 4;
- bool SourceCodeInfo_Location::has_trailing_comments() const {
+bool SourceCodeInfo_Location::has_trailing_comments() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void SourceCodeInfo_Location::set_has_trailing_comments() {
+void SourceCodeInfo_Location::set_has_trailing_comments() {
   _has_bits_[0] |= 0x00000008u;
 }
- void SourceCodeInfo_Location::clear_has_trailing_comments() {
+void SourceCodeInfo_Location::clear_has_trailing_comments() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void SourceCodeInfo_Location::clear_trailing_comments() {
+void SourceCodeInfo_Location::clear_trailing_comments() {
   trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_trailing_comments();
 }
@@ -12983,10 +14023,10 @@
 }
 
 // repeated string leading_detached_comments = 6;
- int SourceCodeInfo_Location::leading_detached_comments_size() const {
+int SourceCodeInfo_Location::leading_detached_comments_size() const {
   return leading_detached_comments_.size();
 }
- void SourceCodeInfo_Location::clear_leading_detached_comments() {
+void SourceCodeInfo_Location::clear_leading_detached_comments() {
   leading_detached_comments_.Clear();
 }
  const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
@@ -13041,33 +14081,839 @@
 // SourceCodeInfo
 
 // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
- int SourceCodeInfo::location_size() const {
+int SourceCodeInfo::location_size() const {
   return location_.size();
 }
- void SourceCodeInfo::clear_location() {
+void SourceCodeInfo::clear_location() {
   location_.Clear();
 }
- const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
+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) {
+::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() {
+::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() {
   // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
   return location_.Add();
 }
- const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
+::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_;
 }
- ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
-SourceCodeInfo::mutable_location() {
-  // @@protoc_insertion_point(field_mutable_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() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<GeneratedCodeInfo_Annotation*>(16)->f)
+
+#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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GeneratedCodeInfo_Annotation* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo_Annotation>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) {
+  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() {
+  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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GeneratedCodeInfo* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) {
+  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() {
+  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
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index d8cba65..3fe07bf 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -38,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,
@@ -155,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 {
@@ -228,10 +251,10 @@
   const ::google::protobuf::FileDescriptorProto& file(int index) const;
   ::google::protobuf::FileDescriptorProto* mutable_file(int index);
   ::google::protobuf::FileDescriptorProto* add_file();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-      file() const;
   ::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:
@@ -384,10 +407,10 @@
   const ::google::protobuf::DescriptorProto& message_type(int index) const;
   ::google::protobuf::DescriptorProto* mutable_message_type(int index);
   ::google::protobuf::DescriptorProto* add_message_type();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-      message_type() const;
   ::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;
   int enum_type_size() const;
@@ -396,10 +419,10 @@
   const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
   ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
   ::google::protobuf::EnumDescriptorProto* add_enum_type();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-      enum_type() const;
   ::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;
   int service_size() const;
@@ -408,10 +431,10 @@
   const ::google::protobuf::ServiceDescriptorProto& service(int index) const;
   ::google::protobuf::ServiceDescriptorProto* mutable_service(int index);
   ::google::protobuf::ServiceDescriptorProto* add_service();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
-      service() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
       mutable_service();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+      service() const;
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
   int extension_size() const;
@@ -420,10 +443,10 @@
   const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
   ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
   ::google::protobuf::FieldDescriptorProto* add_extension();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-      extension() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
       mutable_extension();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+      extension() const;
 
   // optional .google.protobuf.FileOptions options = 8;
   bool has_options() const;
@@ -591,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();
@@ -654,6 +776,7 @@
   // nested types ----------------------------------------------------
 
   typedef DescriptorProto_ExtensionRange ExtensionRange;
+  typedef DescriptorProto_ReservedRange ReservedRange;
 
   // accessors -------------------------------------------------------
 
@@ -676,10 +799,10 @@
   const ::google::protobuf::FieldDescriptorProto& field(int index) const;
   ::google::protobuf::FieldDescriptorProto* mutable_field(int index);
   ::google::protobuf::FieldDescriptorProto* add_field();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-      field() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
       mutable_field();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+      field() const;
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
   int extension_size() const;
@@ -688,10 +811,10 @@
   const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
   ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
   ::google::protobuf::FieldDescriptorProto* add_extension();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-      extension() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
       mutable_extension();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+      extension() const;
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
   int nested_type_size() const;
@@ -700,10 +823,10 @@
   const ::google::protobuf::DescriptorProto& nested_type(int index) const;
   ::google::protobuf::DescriptorProto* mutable_nested_type(int index);
   ::google::protobuf::DescriptorProto* add_nested_type();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-      nested_type() const;
   ::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;
   int enum_type_size() const;
@@ -712,10 +835,10 @@
   const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
   ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
   ::google::protobuf::EnumDescriptorProto* add_enum_type();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-      enum_type() const;
   ::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;
   int extension_range_size() const;
@@ -724,10 +847,10 @@
   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();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
-      extension_range() const;
   ::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;
   int oneof_decl_size() const;
@@ -736,10 +859,10 @@
   const ::google::protobuf::OneofDescriptorProto& oneof_decl(int index) const;
   ::google::protobuf::OneofDescriptorProto* mutable_oneof_decl(int index);
   ::google::protobuf::OneofDescriptorProto* add_oneof_decl();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
-      oneof_decl() const;
   ::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;
   bool has_options() const;
@@ -750,6 +873,34 @@
   ::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:
   inline void set_has_name();
@@ -768,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();
@@ -982,6 +1135,18 @@
   ::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;
   bool has_options() const;
   void clear_options();
@@ -1009,6 +1174,8 @@
   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();
 
@@ -1023,6 +1190,7 @@
   int type_;
   ::google::protobuf::int32 oneof_index_;
   ::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();
@@ -1210,10 +1378,10 @@
   const ::google::protobuf::EnumValueDescriptorProto& value(int index) const;
   ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index);
   ::google::protobuf::EnumValueDescriptorProto* add_value();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
-      value() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
       mutable_value();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+      value() const;
 
   // optional .google.protobuf.EnumOptions options = 3;
   bool has_options() const;
@@ -1445,10 +1613,10 @@
   const ::google::protobuf::MethodDescriptorProto& method(int index) const;
   ::google::protobuf::MethodDescriptorProto* mutable_method(int index);
   ::google::protobuf::MethodDescriptorProto* add_method();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
-      method() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
       mutable_method();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+      method() const;
 
   // optional .google.protobuf.ServiceOptions options = 3;
   bool has_options() const;
@@ -1837,6 +2005,25 @@
   ::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);
+
+  // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+  bool has_javanano_use_deprecated_package() const PROTOBUF_DEPRECATED;
+  void clear_javanano_use_deprecated_package() PROTOBUF_DEPRECATED;
+  static const int kJavananoUseDeprecatedPackageFieldNumber = 38;
+  bool javanano_use_deprecated_package() const PROTOBUF_DEPRECATED;
+  void set_javanano_use_deprecated_package(bool value) PROTOBUF_DEPRECATED;
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   int uninterpreted_option_size() const;
   void clear_uninterpreted_option();
@@ -1844,10 +2031,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -1878,6 +2065,10 @@
   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();
+  inline void set_has_javanano_use_deprecated_package();
+  inline void clear_has_javanano_use_deprecated_package();
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
@@ -1892,12 +2083,14 @@
   bool cc_generic_services_;
   int optimize_for_;
   ::google::protobuf::internal::ArenaStringPtr go_package_;
-  ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_;
-  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   bool java_generic_services_;
   bool py_generic_services_;
   bool deprecated_;
   bool cc_enable_arenas_;
+  bool javanano_use_deprecated_package_;
+  ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_;
+  ::google::protobuf::internal::ArenaStringPtr csharp_namespace_;
+  ::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();
@@ -2006,10 +2199,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -2129,6 +2322,31 @@
     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];
@@ -2145,6 +2363,13 @@
   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];
   bool has_lazy() const;
   void clear_lazy();
@@ -2173,10 +2398,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -2185,6 +2410,8 @@
   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();
@@ -2198,11 +2425,12 @@
   ::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_;
-  ::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();
@@ -2297,10 +2525,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -2405,10 +2633,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -2510,10 +2738,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -2615,10 +2843,10 @@
   const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
   ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
   ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
   ::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)
@@ -2822,10 +3050,10 @@
   const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const;
   ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index);
   ::google::protobuf::UninterpretedOption_NamePart* add_name();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
-      name() const;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
       mutable_name();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
+      name() const;
 
   // optional string identifier_value = 3;
   bool has_identifier_value() const;
@@ -3145,10 +3373,10 @@
   const ::google::protobuf::SourceCodeInfo_Location& location(int index) const;
   ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index);
   ::google::protobuf::SourceCodeInfo_Location* add_location();
-  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
-      location() const;
   ::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:
@@ -3164,6 +3392,228 @@
   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_;
+};
 // ===================================================================
 
 
@@ -3191,16 +3641,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -3445,16 +3895,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 {
@@ -3475,16 +3925,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 {
@@ -3505,16 +3955,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 {
@@ -3535,16 +3985,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 {
@@ -3739,6 +4189,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;
@@ -3813,16 +4315,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 {
@@ -3843,16 +4345,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 {
@@ -3873,16 +4375,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 {
@@ -3903,16 +4405,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 {
@@ -3933,16 +4435,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 {
@@ -3963,16 +4465,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 {
@@ -4017,6 +4519,90 @@
   // @@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() {
+  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
@@ -4331,16 +4917,69 @@
   // @@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() {
+  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();
@@ -4507,16 +5146,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 {
@@ -4761,16 +5400,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 {
@@ -5502,6 +6141,83 @@
   // @@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() {
+  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)
+}
+
+// optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+inline bool FileOptions::has_javanano_use_deprecated_package() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void FileOptions::set_has_javanano_use_deprecated_package() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void FileOptions::clear_has_javanano_use_deprecated_package() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void FileOptions::clear_javanano_use_deprecated_package() {
+  javanano_use_deprecated_package_ = false;
+  clear_has_javanano_use_deprecated_package();
+}
+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 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)
+}
+
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
 inline int FileOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
@@ -5521,16 +6237,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5651,16 +6367,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5715,16 +6431,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();
@@ -5741,13 +6482,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;
@@ -5765,13 +6506,13 @@
 
 // optional bool weak = 10 [default = false];
 inline bool FieldOptions::has_weak() const {
-  return (_has_bits_[0] & 0x00000010u) != 0;
+  return (_has_bits_[0] & 0x00000020u) != 0;
 }
 inline void FieldOptions::set_has_weak() {
-  _has_bits_[0] |= 0x00000010u;
+  _has_bits_[0] |= 0x00000020u;
 }
 inline void FieldOptions::clear_has_weak() {
-  _has_bits_[0] &= ~0x00000010u;
+  _has_bits_[0] &= ~0x00000020u;
 }
 inline void FieldOptions::clear_weak() {
   weak_ = false;
@@ -5806,16 +6547,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5888,16 +6629,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5946,16 +6687,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -6004,16 +6745,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -6062,16 +6803,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_;
+}
 
 // -------------------------------------------------------------------
 
@@ -6177,16 +6918,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 {
@@ -6666,18 +7407,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() {
+  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)
 
@@ -6708,6 +7664,11 @@
 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 protobuf
 }  // namespace google
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 367b16e..3e664d5 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -40,8 +40,11 @@
 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.
@@ -104,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.
@@ -175,6 +190,12 @@
   // 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;
 }
 
@@ -249,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.
@@ -285,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
@@ -351,6 +374,13 @@
   // 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;
+
+  // Whether the nano proto compiler should generate in the deprecated non-nano
+  // suffixed package.
+  optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -437,10 +467,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
@@ -482,7 +533,6 @@
   optional bool weak = 10 [default=false];
 
 
-
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -727,3 +777,29 @@
     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.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 1c03c44..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_;
 };
 
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index fdce3d7..be8e0b7 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,8 @@
 #include <google/protobuf/stubs/substitute.h>
 
 #include <google/protobuf/stubs/common.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 +145,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 +178,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 +429,37 @@
   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");
@@ -420,6 +520,16 @@
     //     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.
     //
@@ -485,6 +595,30 @@
              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);
@@ -495,6 +629,9 @@
     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);
 
@@ -521,6 +658,14 @@
 
     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_;
@@ -528,10 +673,12 @@
   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_;
 
@@ -623,6 +770,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());
@@ -1720,6 +1896,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.
@@ -1781,7 +2035,7 @@
     return field != NULL ? field->enum_type() : NULL;
   }
 
-  scoped_ptr<DescriptorPool> pool_;
+  google::protobuf::scoped_ptr<DescriptorPool> pool_;
 };
 
 TEST_F(MiscTest, TypeNames) {
@@ -2211,7 +2465,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) {
@@ -2921,86 +3175,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
@@ -3251,6 +3523,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\" "
@@ -3399,6 +3767,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\" "
@@ -4767,7 +5196,6 @@
 }
 
 TEST_F(ValidationErrorTest, UnusedImportWarning) {
-
   pool_.AddUnusedImportTrackFile("bar.proto");
   BuildFile(
     "name: \"bar.proto\" "
@@ -4799,7 +5227,7 @@
   // }
   //
   pool_.AddUnusedImportTrackFile("forward.proto");
-  BuildFile(
+  BuildFileWithWarnings(
     "name: \"forward.proto\""
     "dependency: \"base.proto\""
     "dependency: \"bar.proto\""
@@ -4809,7 +5237,8 @@
     "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 {
@@ -5145,6 +5574,35 @@
       "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' "
@@ -5293,6 +5751,22 @@
       "in proto3.\n");
 }
 
+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.
@@ -5360,6 +5834,32 @@
       "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
 
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
new file mode 100644
index 0000000..b325944
--- /dev/null
+++ b/src/google/protobuf/duration.pb.cc
@@ -0,0 +1,408 @@
+// 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(\005BP\n\023com.google.protobufB\rDu"
+    "rationProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf"
+    ".WellKnownTypesb\006proto3", 183);
+  ::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() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Duration*>(16)->f)
+
+#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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Duration* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Duration>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Duration::MergeFrom(const Duration& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Duration::CopyFrom(const Duration& from) {
+  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
index 868c732..78bcc74 100644
--- a/src/google/protobuf/duration.proto
+++ b/src/google/protobuf/duration.proto
@@ -27,15 +27,17 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (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 java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "DurationProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 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
@@ -44,7 +46,7 @@
 // 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.
+// Example 1: Compute Duration from two Timestamps in pseudo code.
 //
 //     Timestamp start = ...;
 //     Timestamp end = ...;
@@ -61,7 +63,7 @@
 //       duration.nanos += 1000000000;
 //     }
 //
-// Example 2: compute Timestamp from Timestamp + Duration in pseudo code.
+// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
 //
 //     Timestamp start = ...;
 //     Duration duration = ...;
@@ -79,15 +81,16 @@
 //     }
 //
 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
+  // `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 318ce6f..8d689ac 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -64,8 +64,13 @@
 
 #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>
@@ -79,6 +84,7 @@
 #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 {
@@ -87,7 +93,7 @@
 using internal::ExtensionSet;
 using internal::GeneratedMessageReflection;
 using internal::MapField;
-using internal::MapFieldBase;
+using internal::DynamicMapField;
 
 
 using internal::ArenaStringPtr;
@@ -116,7 +122,7 @@
       case FD::CPPTYPE_ENUM   : return sizeof(RepeatedField<int     >);
       case FD::CPPTYPE_MESSAGE:
         if (IsMapFieldInApi(field)) {
-          return sizeof(MapFieldBase);
+          return sizeof(DynamicMapField);
         } else {
           return sizeof(RepeatedPtrField<Message>);
         }
@@ -227,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
@@ -389,7 +395,8 @@
           new(field_ptr) Message*(NULL);
         } else {
           if (IsMapFieldInApi(field)) {
-            new (field_ptr) MapFieldBase();
+            new (field_ptr) DynamicMapField(
+                type_info_->factory->GetPrototypeNoLock(field->message_type()));
           } else {
             new (field_ptr) RepeatedPtrField<Message>();
           }
@@ -412,7 +419,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
@@ -437,8 +444,8 @@
                   &(reinterpret_cast<const ArenaStringPtr*>(
                       type_info_->prototype->OffsetToPointer(
                           type_info_->offsets[i]))->Get(NULL));
-              reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value,
-                                                                    NULL);
+              reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
+                  default_value, NULL);
               break;
             }
           }
@@ -480,7 +487,7 @@
 
         case FieldDescriptor::CPPTYPE_MESSAGE:
           if (IsMapFieldInApi(field)) {
-            reinterpret_cast<MapFieldBase*>(field_ptr)->~MapFieldBase();
+            reinterpret_cast<DynamicMapField*>(field_ptr)->~DynamicMapField();
           } else {
             reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
                 ->~RepeatedPtrField<Message>();
@@ -496,8 +503,8 @@
               &(reinterpret_cast<const ArenaStringPtr*>(
                   type_info_->prototype->OffsetToPointer(
                       type_info_->offsets[i]))->Get(NULL));
-          reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value,
-                                                                NULL);
+          reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
+              default_value, NULL);
           break;
         }
       }
@@ -723,8 +730,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) {
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
index b5928a5..f74cd7d 100644
--- a/src/google/protobuf/dynamic_message.h
+++ b/src/google/protobuf/dynamic_message.h
@@ -45,6 +45,7 @@
 
 #include <google/protobuf/message.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 522a092..70e437d 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -40,6 +40,12 @@
 // 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>
@@ -48,6 +54,7 @@
 #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>
 
@@ -142,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());
@@ -151,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());
@@ -160,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());
@@ -169,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();
@@ -230,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();
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
new file mode 100644
index 0000000..f2eec78
--- /dev/null
+++ b/src/google/protobuf/empty.pb.cc
@@ -0,0 +1,310 @@
+// 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\005EmptyBP\n\023com.google.protobufB\n"
+    "EmptyProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Protob"
+    "uf.WellKnownTypesb\006proto3", 145);
+  ::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() {
+}
+
+bool Empty::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Empty* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Empty>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Empty::MergeFrom(const Empty& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+}
+
+void Empty::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Empty::CopyFrom(const Empty& from) {
+  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..b96daf2
--- /dev/null
+++ b/src/google/protobuf/empty.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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+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 03b38dd..9afb236 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -314,7 +314,7 @@
     extension->is_repeated = true;                                             \
     extension->is_packed = packed;                                             \
     extension->repeated_##LOWERCASE##_value =                                  \
-      Arena::Create<RepeatedField<LOWERCASE> >(arena_, arena_);                \
+      Arena::CreateMessage<RepeatedField<LOWERCASE> >(arena_);                 \
   } else {                                                                     \
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE);                              \
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);                                   \
@@ -359,43 +359,43 @@
         static_cast<WireFormatLite::FieldType>(field_type))) {
       case WireFormatLite::CPPTYPE_INT32:
         extension->repeated_int32_value =
-            Arena::Create<RepeatedField<int32> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<int32> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_INT64:
         extension->repeated_int64_value =
-            Arena::Create<RepeatedField<int64> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<int64> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT32:
         extension->repeated_uint32_value =
-            Arena::Create<RepeatedField<uint32> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<uint32> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT64:
         extension->repeated_uint64_value =
-            Arena::Create<RepeatedField<uint64> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<uint64> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_DOUBLE:
         extension->repeated_double_value =
-            Arena::Create<RepeatedField<double> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<double> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_FLOAT:
         extension->repeated_float_value =
-            Arena::Create<RepeatedField<float> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<float> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_BOOL:
         extension->repeated_bool_value =
-            Arena::Create<RepeatedField<bool> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<bool> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_ENUM:
         extension->repeated_enum_value =
-            Arena::Create<RepeatedField<int> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<int> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_STRING:
         extension->repeated_string_value =
-            Arena::Create<RepeatedPtrField< ::std::string> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedPtrField< ::std::string> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_MESSAGE:
         extension->repeated_message_value =
-            Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
         break;
     }
   }
@@ -468,7 +468,7 @@
     extension->is_repeated = true;
     extension->is_packed = packed;
     extension->repeated_enum_value =
-        Arena::Create<RepeatedField<int> >(arena_, arena_);
+        Arena::CreateMessage<RepeatedField<int> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);
@@ -529,7 +529,7 @@
     extension->is_repeated = true;
     extension->is_packed = false;
     extension->repeated_string_value =
-        Arena::Create<RepeatedPtrField<string> >(arena_, arena_);
+        Arena::CreateMessage<RepeatedPtrField<string> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
   }
@@ -595,20 +595,21 @@
     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->GetArena() == arena_) {
+    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);
-      if (message->GetArena() == NULL) {
-        delete message;
-      }
     }
   } else {
     GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
@@ -618,20 +619,49 @@
       if (arena_ == NULL) {
         delete extension->message_value;
       }
-      if (message->GetArena() == arena_) {
+      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);
-        if (message->GetArena() == NULL) {
-          delete 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;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    extension->message_value = message;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message);
+    } else {
+      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);
@@ -712,7 +742,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
     extension->is_repeated = true;
     extension->repeated_message_value =
-        Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+        Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
   }
@@ -866,7 +896,7 @@
       case WireFormatLite::CPPTYPE_##UPPERCASE:                             \
         if (is_new) {                                                       \
           extension->repeated_##LOWERCASE##_value =                         \
-            Arena::Create<REPEATED_TYPE >(arena_, arena_);                  \
+            Arena::CreateMessage<REPEATED_TYPE >(arena_);                   \
         }                                                                   \
         extension->repeated_##LOWERCASE##_value->MergeFrom(                 \
           *other_extension.repeated_##LOWERCASE##_value);                   \
@@ -886,7 +916,7 @@
       case WireFormatLite::CPPTYPE_MESSAGE:
         if (is_new) {
           extension->repeated_message_value =
-              Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+              Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
         }
         // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
         // it would attempt to allocate new objects.
@@ -1718,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 6d6702b..bca179b 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -45,6 +45,8 @@
 
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/once.h>
 
 #include <google/protobuf/repeated_field.h>
 
@@ -194,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
@@ -262,6 +264,9 @@
   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);
@@ -327,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);
@@ -432,6 +439,7 @@
         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;
@@ -574,6 +582,10 @@
   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,
@@ -712,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_;
@@ -755,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##_;                                    \
 }                                                                          \
@@ -808,6 +821,8 @@
   }
 };
 
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_string_type_traits_once_init_;
+
 class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
  public:
   typedef const string& ConstType;
@@ -851,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_;
 };
 
@@ -1015,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 {
@@ -1022,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 796e7a5..82e3e09 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -213,18 +213,23 @@
   }
 }
 
-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 =
-        ::google::protobuf::Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+        ::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.
@@ -244,6 +249,13 @@
   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 684ce00..f40fcbc 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -44,6 +44,7 @@
 #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>
@@ -173,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
@@ -359,9 +360,8 @@
   unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
   message->SetAllocatedExtension(unittest::optional_foreign_message_extension,
                                  foreign_message);
-  // foreign_message is copied underneath, as foreign_message is on heap
-  // and extension_set is on an arena.
-  EXPECT_NE(foreign_message,
+  // foreign_message is now owned by the arena.
+  EXPECT_EQ(foreign_message,
             message->MutableExtension(
                 unittest::optional_foreign_message_extension));
 
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
new file mode 100644
index 0000000..01a6ce5
--- /dev/null
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -0,0 +1,396 @@
+// 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() {
+  paths_.Clear();
+}
+
+bool FieldMask::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FieldMask* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldMask>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void FieldMask::MergeFrom(const FieldMask& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  paths_.MergeFrom(from.paths_);
+}
+
+void FieldMask::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FieldMask::CopyFrom(const FieldMask& from) {
+  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() {
+  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..7189fd7
--- /dev/null
+++ b/src/google/protobuf/field_mask.pb.h
@@ -0,0 +1,201 @@
+// 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() {
+  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
index 492d4b0..908c8a8 100644
--- a/src/google/protobuf/field_mask.proto
+++ b/src/google/protobuf/field_mask.proto
@@ -27,14 +27,17 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (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 java_multiple_files = true;
-option java_outer_classname = "FieldMaskProto";
+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:
 //
@@ -50,6 +53,7 @@
 // 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
@@ -66,7 +70,7 @@
 //     z: 8
 //
 // The result will not contain specific values for fields x,y and z
-// (there value will be set to the default, and omitted in proto text
+// (their value will be set to the default, and omitted in proto text
 // output):
 //
 //
@@ -95,6 +99,7 @@
 // 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
@@ -122,11 +127,13 @@
 // 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.
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 412c48a..eee024e 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -35,6 +35,7 @@
 #include <algorithm>
 #include <set>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
@@ -57,18 +58,6 @@
 }
 }  // anonymous namespace
 
-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();
-  }
-}
-
 bool ParseNamedEnum(const EnumDescriptor* descriptor,
                     const string& name,
                     int* value) {
@@ -818,7 +807,16 @@
         }
 
         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;
       }
     }
@@ -1649,6 +1647,25 @@
   }
 }
 
+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,
@@ -1675,6 +1692,37 @@
   }
 }
 
+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(
     const Message& message,
     const OneofDescriptor* oneof_descriptor) const {
@@ -1685,6 +1733,69 @@
   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)->InsertMapValue(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(
@@ -2098,6 +2209,14 @@
   }
 }
 
+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,
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index 4dddf6c..9ef7871 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -40,6 +40,7 @@
 
 #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.
@@ -57,7 +58,9 @@
 }  // namespace upb
 
 namespace protobuf {
-  class DescriptorPool;
+class DescriptorPool;
+class MapKey;
+class MapValueRef;
 }
 
 namespace protobuf {
@@ -260,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;
@@ -370,6 +392,9 @@
                     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;
@@ -390,10 +415,15 @@
   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(
@@ -406,7 +436,7 @@
 
   // 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_;
@@ -538,6 +568,9 @@
                                       Message* sub_message,
                                       const FieldDescriptor* field) const;
 
+  internal::MapFieldBase* MapData(
+      Message* message, const FieldDescriptor* field) const;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
 };
 
@@ -597,6 +630,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(_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 53cae8b..7b813f8 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -60,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..78c8d7f 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -47,6 +47,10 @@
 namespace google {
 
 namespace protobuf {
+
+class Arena;
+namespace io { class CodedInputStream; }
+
 namespace internal {
 
 
@@ -85,12 +89,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 +104,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 93e1a22..e3a34d0 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -44,6 +44,7 @@
 #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>
 
@@ -156,6 +157,11 @@
   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);
@@ -164,6 +170,12 @@
   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();
@@ -245,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) {
@@ -336,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;
@@ -364,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;
   }
 }
 
@@ -425,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
@@ -479,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.
@@ -517,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);
   }
 }
 
@@ -612,6 +629,24 @@
   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();
 }
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index dea4b65..e377100 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -109,14 +109,15 @@
 #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)
@@ -191,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
@@ -207,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.
@@ -238,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
@@ -248,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
@@ -258,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
@@ -267,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
@@ -387,9 +392,14 @@
   // 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
@@ -398,15 +408,25 @@
   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);
-  //  DecrementRecursionDepth();
+  //  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.
   //
@@ -568,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);
@@ -578,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);
 
@@ -642,6 +666,7 @@
  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.
@@ -742,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);
@@ -807,8 +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* 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);
 };
@@ -818,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) {
@@ -832,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
@@ -903,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(
@@ -918,10 +952,12 @@
   // 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];
@@ -948,7 +984,7 @@
     }
   }
   // Slow path
-  last_tag_ = ReadTagFallback();
+  last_tag_ = ReadTagFallback(first_byte_or_zero);
   return std::make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
 }
 
@@ -1001,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() {
@@ -1177,6 +1213,11 @@
   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,
                                                    MessageFactory* factory) {
   extension_pool_ = pool;
@@ -1192,7 +1233,7 @@
 }
 
 inline int CodedInputStream::BufferSize() const {
-  return buffer_end_ - buffer_;
+  return static_cast<int>(buffer_end_ - buffer_);
 }
 
 inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
@@ -1245,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 cd8d174..d95b06e 100644
--- a/src/google/protobuf/io/coded_stream_inl.h
+++ b/src/google/protobuf/io/coded_stream_inl.h
@@ -36,6 +36,7 @@
 #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>
@@ -66,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 02d5bad..d1782e3 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/scoped_ptr.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -677,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 77d485c..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 {
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index e621ba1..7d88650 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 {
@@ -155,6 +156,78 @@
   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_ += "  ";
 }
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index 92ce340..f1490bb 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -91,8 +91,36 @@
                                const char* variable2, const string& value2,
                                const char* variable3, const string& value3,
                                const char* variable4, const string& value4);
-  // 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,
+                               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
diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc
index 1331a8d..258dd98 100644
--- a/src/google/protobuf/io/printer_unittest.cc
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/io/printer.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/testing/googletest.h>
 #include <gtest/gtest.h>
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..3d57707 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
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
index 98576f5..49885ed 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 {
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index de096fb..20d50a2 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>
@@ -874,6 +875,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 97b73b8..083beca 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -39,6 +39,7 @@
 
 #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 {
@@ -156,6 +157,7 @@
 }
 
 bool StringOutputStream::Next(void** data, int* size) {
+  GOOGLE_CHECK_NE(NULL, target_);
   int old_size = target_->size();
 
   // Grow the string.
@@ -187,14 +189,44 @@
 
 void StringOutputStream::BackUp(int count) {
   GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK_NE(NULL, target_);
   GOOGLE_CHECK_LE(count, target_->size());
   target_->resize(target_->size() - count);
 }
 
 int64 StringOutputStream::ByteCount() const {
+  GOOGLE_CHECK_NE(NULL, target_);
   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() {}
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 4360b18..1c397de 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,15 @@
 #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/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 
@@ -143,6 +148,9 @@
   void BackUp(int count);
   int64 ByteCount() const;
 
+ protected:
+  void SetString(string* target);
+
  private:
   static const int kMinimumSize = 16;
 
@@ -151,6 +159,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 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());
@@ -234,7 +263,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
@@ -323,7 +352,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
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc
index dd3d128..8c7358c 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,6 +57,10 @@
 #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>
@@ -68,6 +71,8 @@
 #endif
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/scoped_ptr.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());
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 4ea2100..d1948ab 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,336 @@
     GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size());
   }
 
+  // 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());
+  }
+
   std::cout << "PASS" << std::endl;
   return 0;
 }
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index e56af3f..dfc6242 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -33,10 +33,14 @@
 
 #include <iterator>
 #include <google/protobuf/stubs/hash.h>
+#include <limits>  // To support Visual Studio 2008
 
+#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>
 
 namespace google {
 namespace protobuf {
@@ -46,13 +50,380 @@
 
 template <typename Enum> struct is_proto_enum;
 
+class MapIterator;
+
 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_) {
+      return false;
+    }
+    switch (type()) {
+      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_;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Can't get here.";
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return false;
+  }
+
+  void CopyFrom(const MapKey& other) {
+    SetType(other.type());
+    switch (type_) {
+      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;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Can't get here.";
+        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
@@ -81,7 +452,6 @@
   T second;
 
  private:
-  typedef void DestructorSkippable_;
   friend class ::google::protobuf::Arena;
   friend class Map<Key, T>;
 };
@@ -91,9 +461,6 @@
 // interface directly to visit or change map fields.
 template <typename Key, typename T>
 class Map {
-  typedef internal::MapCppTypeHandler<Key> KeyTypeHandler;
-  typedef internal::MapCppTypeHandler<T> ValueTypeHandler;
-
  public:
   typedef Key key_type;
   typedef T mapped_type;
@@ -117,7 +484,9 @@
       : arena_(arena),
         allocator_(arena_),
         elements_(0, hasher(), key_equal(), allocator_),
-        default_enum_value_(0) {}
+        default_enum_value_(0) {
+    arena_->OwnDestructor(&elements_);
+  }
 
   Map(const Map& other)
       : arena_(NULL),
@@ -126,6 +495,14 @@
         default_enum_value_(other.default_enum_value_) {
     insert(other.begin(), other.end());
   }
+  template <class InputIt>
+  Map(const InputIt& first, const InputIt& last)
+      : arena_(NULL),
+        allocator_(arena_),
+        elements_(0, hasher(), key_equal(), allocator_),
+        default_enum_value_(0) {
+    insert(first, last);
+  }
 
   ~Map() { clear(); }
 
@@ -167,11 +544,22 @@
       }
     }
 
+#if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \
+    !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID)
+    template<class NodeType, class... Args>
+    void construct(NodeType* p, Args&&... args) {
+      new (static_cast<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) {
-      if (arena_ == NULL) p->~value_type();
-    }
+    void destroy(pointer p) { p->~value_type(); }
+#endif
 
     template <typename X>
     struct rebind {
@@ -188,22 +576,29 @@
       return arena_ != other.arena_;
     }
 
+    // To support Visual Studio 2008
+    size_type max_size() const {
+      return std::numeric_limits<size_type>::max();
+    }
+
    private:
-    Arena* arena_;
+    typedef void DestructorSkippable_;
+    Arena* const arena_;
 
     template <typename X>
     friend class MapAllocator;
   };
 
- public:
   typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator;
+  typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator>
+      InnerMap;
 
+ public:
   // Iterators
-  class LIBPROTOBUF_EXPORT const_iterator
+  class const_iterator
       : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
                              const value_type*, const value_type&> {
-    typedef typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
-                              Allocator>::const_iterator InnerIt;
+    typedef typename InnerMap::const_iterator InnerIt;
 
    public:
     const_iterator() {}
@@ -229,9 +624,8 @@
     InnerIt it_;
   };
 
-  class LIBPROTOBUF_EXPORT iterator : public std::iterator<std::forward_iterator_tag, value_type> {
-    typedef typename hash_map<Key, value_type*, hasher, equal_to<Key>,
-                              Allocator>::iterator InnerIt;
+  class iterator : public std::iterator<std::forward_iterator_tag, value_type> {
+    typedef typename InnerMap::iterator InnerIt;
 
    public:
     iterator() {}
@@ -347,8 +741,7 @@
 
   // Erase
   size_type erase(const key_type& key) {
-    typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
-                      Allocator>::iterator it = elements_.find(key);
+    typename InnerMap::iterator it = elements_.find(key);
     if (it == elements_.end()) {
       return 0;
     } else {
@@ -418,19 +811,74 @@
 
   Arena* arena_;
   Allocator allocator_;
-  hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> elements_;
+  InnerMap elements_;
   int default_enum_value_;
 
   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 LIBPROTOBUF_EXPORT internal::MapFieldLite;
+  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_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());
+      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.";
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
+  }
+  bool
+  operator()(const google::protobuf::MapKey& map_key1,
+             const google::protobuf::MapKey& map_key2) const {
+    switch (map_key1.type()) {
+#define COMPARE_CPPTYPE(CPPTYPE, CPPTYPE_METHOD)             \
+      case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: \
+        return map_key1.Get##CPPTYPE_METHOD##Value() <           \
+               map_key2.Get##CPPTYPE_METHOD##Value();
+      COMPARE_CPPTYPE(STRING, String)
+      COMPARE_CPPTYPE(INT64,  Int64)
+      COMPARE_CPPTYPE(INT32,  Int32)
+      COMPARE_CPPTYPE(UINT64, UInt64)
+      COMPARE_CPPTYPE(UINT32, UInt32)
+      COMPARE_CPPTYPE(BOOL,   Bool)
+#undef COMPARE_CPPTYPE
+      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.";
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return true;
+  }
+};
+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
index f78a4f4..987c4e2 100644
--- a/src/google/protobuf/map_entry.h
+++ b/src/google/protobuf/map_entry.h
@@ -34,6 +34,7 @@
 #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>
@@ -79,40 +80,46 @@
 
 // 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 internal layout is the same as generated message with the
-// same fields. However, in order to decide the internal layout of key/value, we
-// need to know both their cpp type in generated api and proto type.
+// 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 | proto type  | internal layout
-// int32      TYPE_INT32    int32
-// int32      TYPE_FIXED32  int32
-// FooEnum    TYPE_ENUM     int
-// FooMessage TYPE_MESSAGE  FooMessage*
+// 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.
 //
-// The internal layouts of primitive types can be inferred from its proto type,
-// while we need to explicitly tell cpp type if proto type is TYPE_MESSAGE to
-// get internal layout.
-// Moreover, default_enum_value is used to initialize enum field in proto2.
+// 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 LIBPROTOBUF_EXPORT MapEntry : public MapEntryBase {
-  // Handlers for key/value wire type. Provide utilities to parse/serialize
-  // key/value.
-  typedef MapWireFieldTypeHandler<kKeyFieldType> KeyWireHandler;
-  typedef MapWireFieldTypeHandler<kValueFieldType> ValueWireHandler;
+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;
 
-  // Define key/value's internal stored type. Message is the only one whose
-  // internal stored type cannot be inferred from its proto type.
-  static const bool kIsKeyMessage = KeyWireHandler::kIsMessage;
-  static const bool kIsValueMessage = ValueWireHandler::kIsMessage;
-  typedef typename KeyWireHandler::CppType KeyInternalType;
-  typedef typename ValueWireHandler::CppType ValueInternalType;
-  typedef typename MapIf<kIsKeyMessage, Key, KeyInternalType>::type
-      KeyCppType;
-  typedef typename MapIf<kIsValueMessage, Value, ValueInternalType>::type
-      ValCppType;
+  // 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<
@@ -132,16 +139,16 @@
 
   // accessors ======================================================
 
-  virtual inline const KeyCppType& key() const {
+  virtual inline const KeyMapEntryAccessorType& key() const {
     return entry_lite_.key();
   }
-  inline KeyCppType* mutable_key() {
+  inline KeyMapEntryAccessorType* mutable_key() {
     return entry_lite_.mutable_key();
   }
-  virtual inline const ValCppType& value() const {
+  virtual inline const ValueMapEntryAccessorType& value() const {
     return entry_lite_.value();
   }
-  inline ValCppType* mutable_value() {
+  inline ValueMapEntryAccessorType* mutable_value() {
     return entry_lite_.mutable_value();
   }
 
@@ -240,7 +247,9 @@
         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), -1);
+        ::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);
@@ -250,10 +259,13 @@
   }
 
  private:
-  MapEntry() : default_instance_(NULL), entry_lite_() {}
+  MapEntry()
+      : _internal_metadata_(NULL), default_instance_(NULL), entry_lite_() {}
 
   explicit MapEntry(Arena* arena)
-      : default_instance_(NULL), entry_lite_(arena) {}
+      : _internal_metadata_(arena),
+        default_instance_(NULL),
+        entry_lite_(arena) {}
 
   inline Arena* GetArenaNoVirtual() const {
     return entry_lite_.GetArenaNoVirtual();
@@ -266,6 +278,7 @@
 
   static int offsets_[2];
   UnknownFieldSet _unknown_fields_;
+  InternalMetadataWithArena _internal_metadata_;
   MapEntry* default_instance_;
   EntryLiteType entry_lite_;
 
@@ -274,8 +287,8 @@
   typedef void DestructorSkippable_;
   template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
             WireFormatLite::FieldType, int default_enum>
-  friend class LIBPROTOBUF_EXPORT internal::MapField;
-  friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection;
+  friend class internal::MapField;
+  friend class internal::GeneratedMessageReflection;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
 };
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 304fba8..7cdf1b9 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -60,39 +60,22 @@
           WireFormatLite::FieldType kKeyFieldType,
           WireFormatLite::FieldType kValueFieldType,
           int default_enum_value>
-class LIBPROTOBUF_EXPORT MapEntryLite : public MessageLite {
-  // Handlers for key/value wire type. Provide utilities to parse/serialize
-  // key/value.
-  typedef MapWireFieldTypeHandler<kKeyFieldType> KeyWireHandler;
-  typedef MapWireFieldTypeHandler<kValueFieldType> ValueWireHandler;
-
-  // Define key/value's internal stored type. Message is the only one whose
-  // internal stored type cannot be inferred from its proto type
-  static const bool kIsKeyMessage = KeyWireHandler::kIsMessage;
-  static const bool kIsValueMessage = ValueWireHandler::kIsMessage;
-  typedef typename KeyWireHandler::CppType KeyInternalType;
-  typedef typename ValueWireHandler::CppType ValueInternalType;
-  typedef typename MapIf<kIsKeyMessage, Key, KeyInternalType>::type
-      KeyCppType;
-  typedef typename MapIf<kIsValueMessage, Value, ValueInternalType>::type
-      ValCppType;
-
-  // Handlers for key/value's internal stored type. Provide utilities to
-  // manipulate internal stored type. We need it because some types are stored
-  // as values and others are stored as pointers (Message and string), but we
-  // need to keep the code in MapEntry unified instead of providing different
-  // codes for each type.
-  typedef MapCppTypeHandler<KeyCppType> KeyCppHandler;
-  typedef MapCppTypeHandler<ValCppType> ValueCppHandler;
+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.
-  static const bool kKeyIsStringOrMessage = KeyCppHandler::kIsStringOrMessage;
-  static const bool kValIsStringOrMessage = ValueCppHandler::kIsStringOrMessage;
-  typedef typename MapIf<kKeyIsStringOrMessage, KeyCppType*, KeyCppType>::type
-      KeyBase;
-  typedef typename MapIf<kValIsStringOrMessage, ValCppType*, ValCppType>::type
-      ValueBase;
+  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;
@@ -100,38 +83,37 @@
 
   // Constants for field tag.
   static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
-      kKeyFieldNumber, KeyWireHandler::kWireType);
+      kKeyFieldNumber, KeyTypeHandler::kWireType);
   static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
-      kValueFieldNumber, ValueWireHandler::kWireType);
+      kValueFieldNumber, ValueTypeHandler::kWireType);
   static const int kTagSize = 1;
 
  public:
   ~MapEntryLite() {
     if (this != default_instance_) {
-      KeyCppHandler::Delete(key_);
-      ValueCppHandler::Delete(value_);
+      if (GetArenaNoVirtual() != NULL) return;
+      KeyTypeHandler::DeleteNoArena(key_);
+      ValueTypeHandler::DeleteNoArena(value_);
     }
   }
 
   // accessors ======================================================
 
-  virtual inline const KeyCppType& key() const {
-    return KeyCppHandler::Reference(key_);
+  virtual inline const KeyMapEntryAccessorType& key() const {
+    return KeyTypeHandler::GetExternalReference(key_);
   }
-  inline KeyCppType* mutable_key() {
-    set_has_key();
-    KeyCppHandler::EnsureMutable(&key_, GetArenaNoVirtual());
-    return KeyCppHandler::Pointer(key_);
-  }
-  virtual inline const ValCppType& value() const {
+  virtual inline const ValueMapEntryAccessorType& value() const {
     GOOGLE_CHECK(default_instance_ != NULL);
-    return ValueCppHandler::DefaultIfNotInitialized(value_,
+    return ValueTypeHandler::DefaultIfNotInitialized(value_,
                                                     default_instance_->value_);
   }
-  inline ValCppType* mutable_value() {
+  inline KeyMapEntryAccessorType* mutable_key() {
+    set_has_key();
+    return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
+  }
+  inline ValueMapEntryAccessorType* mutable_value() {
     set_has_value();
-    ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual());
-    return ValueCppHandler::Pointer(value_);
+    return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
   }
 
   // implements MessageLite =========================================
@@ -159,13 +141,17 @@
       tag = input->ReadTag();
       switch (tag) {
         case kKeyTag:
-          if (!KeyWireHandler::Read(input, mutable_key())) return false;
+          if (!KeyTypeHandler::Read(input, mutable_key())) {
+            return false;
+          }
           set_has_key();
           if (!input->ExpectTag(kValueTag)) break;
           GOOGLE_FALLTHROUGH_INTENDED;
 
         case kValueTag:
-          if (!ValueWireHandler::Read(input, mutable_value())) return false;
+          if (!ValueTypeHandler::Read(input, mutable_value())) {
+            return false;
+          }
           set_has_value();
           if (input->ExpectAtEnd()) return true;
           break;
@@ -184,32 +170,35 @@
 
   int ByteSize() const {
     int size = 0;
-    size += has_key() ? kTagSize + KeyWireHandler::ByteSize(key()) : 0;
-    size += has_value() ? kTagSize + ValueWireHandler::ByteSize(value()) : 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 {
-    KeyWireHandler::Write(kKeyFieldNumber, key(), output);
-    ValueWireHandler::Write(kValueFieldNumber, value(), output);
+    KeyTypeHandler::Write(kKeyFieldNumber, key(), output);
+    ValueTypeHandler::Write(kValueFieldNumber, value(), output);
   }
 
   ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
-    output = KeyWireHandler::WriteToArray(kKeyFieldNumber, key(), output);
-    output =
-        ValueWireHandler::WriteToArray(kValueFieldNumber, value(), output);
+    output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output);
+    output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output);
     return output;
   }
 
   int GetCachedSize() const {
     int size = 0;
-    size += has_key() ? kTagSize + KeyWireHandler::GetCachedSize(key()) : 0;
-    size +=
-        has_value() ? kTagSize + ValueWireHandler::GetCachedSize(value()) : 0;
+    size += has_key()
+        ? kTagSize + KeyTypeHandler::GetCachedSize(key())
+        : 0;
+    size += has_value()
+        ? kTagSize + ValueTypeHandler::GetCachedSize(
+            value())
+        : 0;
     return size;
   }
 
-  bool IsInitialized() const { return ValueCppHandler::IsInitialized(value_); }
+  bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); }
 
   MessageLite* New() const {
     MapEntryLite* entry = new MapEntryLite;
@@ -225,36 +214,37 @@
 
   int SpaceUsed() const {
     int size = sizeof(MapEntryLite);
-    size += KeyCppHandler::SpaceUsedInMapEntry(key_);
-    size += ValueCppHandler::SpaceUsedInMapEntry(value_);
+    size += KeyTypeHandler::SpaceUsedInMapEntry(key_);
+    size += ValueTypeHandler::SpaceUsedInMapEntry(value_);
     return size;
   }
 
   void MergeFrom(const MapEntryLite& from) {
     if (from._has_bits_[0]) {
       if (from.has_key()) {
-        KeyCppHandler::EnsureMutable(&key_, GetArenaNoVirtual());
-        KeyCppHandler::Merge(from.key(), &key_);
+        KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
+        KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual());
         set_has_key();
       }
       if (from.has_value()) {
-        ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual());
-        ValueCppHandler::Merge(from.value(), &value_);
+        ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
+        ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual());
         set_has_value();
       }
     }
   }
 
   void Clear() {
-    KeyCppHandler::Clear(&key_);
-    ValueCppHandler::ClearMaybeByDefaultEnum(&value_, default_enum_value);
+    KeyTypeHandler::Clear(&key_, GetArenaNoVirtual());
+    ValueTypeHandler::ClearMaybeByDefaultEnum(
+        &value_, GetArenaNoVirtual(), default_enum_value);
     clear_has_key();
     clear_has_value();
   }
 
   void InitAsDefaultInstance() {
-    KeyCppHandler::AssignDefaultValue(&key_);
-    ValueCppHandler::AssignDefaultValue(&value_);
+    KeyTypeHandler::AssignDefaultValue(&key_);
+    ValueTypeHandler::AssignDefaultValue(&value_);
   }
 
   Arena* GetArena() const {
@@ -267,17 +257,18 @@
   // 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::Create<MapEnumEntryWrapper<
+    return Arena::CreateMessage<MapEnumEntryWrapper<
         Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >(
-        arena, key, value, arena);
+        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::Create<MapEntryWrapper<Key, Value, kKeyFieldType,
-                                         kValueFieldType, default_enum_value> >(
-        arena, key, value, arena);
+    return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType,
+                                                kValueFieldType,
+                                                default_enum_value> >(
+        arena, key, value);
   }
 
  protected:
@@ -301,28 +292,29 @@
   // 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 LIBPROTOBUF_EXPORT MapEntryWrapper
+  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::KeyCppType KeyCppType;
-    typedef typename Base::ValCppType ValCppType;
+    typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType;
+    typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType;
 
    public:
-    MapEntryWrapper(const K& key, const V& value, Arena* arena)
+    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 KeyCppType& key() const { return key_; }
-    inline const ValCppType& value() const { return 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_;
   };
 
@@ -334,42 +326,42 @@
   // the temporary.
   template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
             WireFormatLite::FieldType v_wire_type, int default_enum>
-  class LIBPROTOBUF_EXPORT MapEnumEntryWrapper
+  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::KeyCppType KeyCppType;
-    typedef typename Base::ValCppType ValCppType;
+    typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType;
+    typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType;
 
    public:
-    MapEnumEntryWrapper(const K& key, const V& value, Arena* arena)
+    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 KeyCppType& key() const { return key_; }
-    inline const ValCppType& value() const { return value_; }
+    inline const KeyMapEntryAccessorType& key() const { return key_; }
+    inline const ValueMapEntryAccessorType& value() const { return value_; }
 
    private:
-    const KeyCppType& key_;
-    const ValCppType value_;
+    const KeyMapEntryAccessorType& key_;
+    const ValueMapEntryAccessorType value_;
 
-    friend class ::google::protobuf::Arena;
+    friend class google::protobuf::Arena;
     typedef void DestructorSkippable_;
   };
 
   MapEntryLite() : default_instance_(NULL), arena_(NULL) {
-    KeyCppHandler::Initialize(&key_, NULL);
-    ValueCppHandler::InitializeMaybeByDefaultEnum(
+    KeyTypeHandler::Initialize(&key_, NULL);
+    ValueTypeHandler::InitializeMaybeByDefaultEnum(
         &value_, default_enum_value, NULL);
     _has_bits_[0] = 0;
   }
 
   explicit MapEntryLite(Arena* arena)
       : default_instance_(NULL), arena_(arena) {
-    KeyCppHandler::Initialize(&key_, arena);
-    ValueCppHandler::InitializeMaybeByDefaultEnum(
+    KeyTypeHandler::Initialize(&key_, arena);
+    ValueTypeHandler::InitializeMaybeByDefaultEnum(
         &value_, default_enum_value, arena);
     _has_bits_[0] = 0;
   }
@@ -384,8 +376,8 @@
 
   MapEntryLite* default_instance_;
 
-  KeyBase key_;
-  ValueBase value_;
+  KeyOnMemory key_;
+  ValueOnMemory value_;
   Arena* arena_;
   uint32 _has_bits_[1];
 
@@ -394,10 +386,10 @@
   typedef void DestructorSkippable_;
   template <typename K, typename V, WireFormatLite::FieldType,
             WireFormatLite::FieldType, int>
-  friend class LIBPROTOBUF_EXPORT internal::MapEntry;
+  friend class internal::MapEntry;
   template <typename K, typename V, WireFormatLite::FieldType,
             WireFormatLite::FieldType, int>
-  friend class LIBPROTOBUF_EXPORT internal::MapFieldLite;
+  friend class internal::MapFieldLite;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
 };
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index fd40c0d..eddc95c 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -29,6 +29,7 @@
 // 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>
 
@@ -104,14 +105,18 @@
 void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; }
 
 void MapFieldBase::SyncRepeatedFieldWithMap() const {
-  Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_);
+  // "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();
-      google::protobuf::internal::NoBarrier_Store(&state_, CLEAN);
+      // "Release" insures state_ can only be changed "after"
+      // SyncRepeatedFieldWithMapNoLock is finished.
+      google::protobuf::internal::Release_Store(&state_, CLEAN);
     }
     mutex_.Unlock();
   }
@@ -119,24 +124,343 @@
 
 void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
   if (repeated_field_ == NULL) {
-    repeated_field_ = Arena::Create<RepeatedPtrField<Message> >(arena_, arena_);
+    repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
   }
 }
 
 void MapFieldBase::SyncMapWithRepeatedField() const {
-  Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_);
+  // "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();
-      google::protobuf::internal::NoBarrier_Store(&state_, CLEAN);
+      // "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::InsertMapValue(
+    const MapKey& map_key, MapValueRef* val) {
+  bool result = false;
+
+  MapValueRef& map_val = (*MutableMap())[map_key];
+  // If map_val.data_ is not set, it is newly inserted by map_[map_key].
+  if (map_val.data_ == NULL) {
+    result = true;
+    const FieldDescriptor* val_des =
+        default_entry_->GetDescriptor()->FindFieldByName("value");
+    map_val.SetType(val_des->cpp_type());
+    // Allocate momery 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 result;
+}
+
+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
index 6d8b6ec..9130166 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -32,6 +32,7 @@
 #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>
@@ -45,7 +46,8 @@
 
 namespace google {
 namespace protobuf {
-
+class DynamicMessage;
+class MapKey;
 namespace internal {
 
 class ContendedMapCleanTest;
@@ -68,7 +70,11 @@
         repeated_field_(NULL),
         entry_descriptor_(NULL),
         assign_descriptor_callback_(NULL),
-        state_(STATE_MODIFIED_MAP) {}
+        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
@@ -79,6 +85,17 @@
   // 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 InsertMapValue(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;
@@ -137,6 +154,57 @@
   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
@@ -146,25 +214,13 @@
           WireFormatLite::FieldType kKeyFieldType,
           WireFormatLite::FieldType kValueFieldType,
           int default_enum_value = 0>
-class LIBPROTOBUF_EXPORT MapField : public MapFieldBase,
+class MapField : public TypeDefinedMapFieldBase<Key, T>,
                  public MapFieldLite<Key, T, kKeyFieldType, kValueFieldType,
                                      default_enum_value> {
-  // Handlers for key/value wire type. Provide utilities to parse/serialize
-  // key/value.
-  typedef MapWireFieldTypeHandler<kKeyFieldType> KeyWireHandler;
-  typedef MapWireFieldTypeHandler<kValueFieldType> ValueWireHandler;
-
-  // Define key/value's internal stored type.
-  static const bool kIsKeyMessage = KeyWireHandler::kIsMessage;
-  static const bool kIsValMessage = ValueWireHandler::kIsMessage;
-  typedef typename KeyWireHandler::CppType KeyInternalType;
-  typedef typename ValueWireHandler::CppType ValueInternalType;
-  typedef typename MapIf<kIsKeyMessage, Key, KeyInternalType>::type KeyCpp;
-  typedef typename MapIf<kIsValMessage, T  , ValueInternalType>::type ValCpp;
-
-  // Handlers for key/value's internal stored type.
-  typedef MapCppTypeHandler<KeyCpp> KeyHandler;
-  typedef MapCppTypeHandler<ValCpp> ValHandler;
+  // 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>
@@ -179,8 +235,8 @@
   // 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
-  // SyncMapWithRepeatedFieldNoLocki.
-  static const bool kIsValueEnum = ValueWireHandler::kIsEnum;
+  // SyncMapWithRepeatedFieldNoLock.
+  static const bool kIsValueEnum = ValueTypeHandler::kIsEnum;
   typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
 
  public:
@@ -193,6 +249,11 @@
   MapField(Arena* arena, const Message* default_entry);
   ~MapField();
 
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const;
+  bool InsertMapValue(const MapKey& map_key, MapValueRef* val);
+  bool DeleteMapValue(const MapKey& map_key);
+
   // Accessors
   const Map<Key, T>& GetMap() const;
   Map<Key, T>* MutableMap();
@@ -208,6 +269,7 @@
   void SetAssignDescriptorCallback(void (*callback)());
 
  private:
+  typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
 
   // MapField needs MapEntry's default instance to create new MapEntry.
@@ -225,12 +287,109 @@
   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 InsertMapValue(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
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
index ae63c72..f116697 100644
--- a/src/google/protobuf/map_field_inl.h
+++ b/src/google/protobuf/map_field_inl.h
@@ -36,12 +36,131 @@
 #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,
@@ -56,7 +175,7 @@
           int default_enum_value>
 MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
     Arena* arena)
-    : MapFieldBase(arena),
+    : TypeDefinedMapFieldBase<Key, T>(arena),
       MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>(
           arena),
       default_entry_(NULL) {}
@@ -75,7 +194,7 @@
           int default_enum_value>
 MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
     Arena* arena, const Message* default_entry)
-    : MapFieldBase(arena),
+    : TypeDefinedMapFieldBase<Key, T>(arena),
       MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>(
           arena),
       default_entry_(down_cast<const EntryType*>(default_entry)) {}
@@ -94,7 +213,7 @@
 int
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::size() const {
-  SyncMapWithRepeatedField();
+  MapFieldBase::SyncMapWithRepeatedField();
   return MapFieldLiteType::GetInternalMap().size();
 }
 
@@ -105,9 +224,65 @@
 void
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::Clear() {
-  SyncMapWithRepeatedField();
+  MapFieldBase::SyncMapWithRepeatedField();
   MapFieldLiteType::MutableInternalMap()->clear();
-  SetMapDirty();
+  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>::InsertMapValue(const MapKey& map_key,
+                                                  MapValueRef* val) {
+  Map<Key, T>* map = MutableMap();
+  bool result = false;
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  if (map->end() == map->find(key)) {
+    result = true;
+  }
+  val->SetValue(&((*map)[key]));
+  return result;
+}
+
+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,
@@ -117,7 +292,7 @@
 const Map<Key, T>&
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::GetMap() const {
-  SyncMapWithRepeatedField();
+  MapFieldBase::SyncMapWithRepeatedField();
   return MapFieldLiteType::GetInternalMap();
 }
 
@@ -128,9 +303,9 @@
 Map<Key, T>*
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::MutableMap() {
-  SyncMapWithRepeatedField();
+  MapFieldBase::SyncMapWithRepeatedField();
   Map<Key, T>* result = MapFieldLiteType::MutableInternalMap();
-  SetMapDirty();
+  MapFieldBase::SetMapDirty();
   return result;
 }
 
@@ -143,10 +318,10 @@
          default_enum_value>::MergeFrom(
     const MapFieldLiteType& other) {
   const MapField& down_other = down_cast<const MapField&>(other);
-  SyncMapWithRepeatedField();
+  MapFieldBase::SyncMapWithRepeatedField();
   down_other.SyncMapWithRepeatedField();
   MapFieldLiteType::MergeFrom(other);
-  SetMapDirty();
+  MapFieldBase::SetMapDirty();
 }
 
 template <typename Key, typename T,
@@ -158,9 +333,9 @@
          default_enum_value>::Swap(
     MapFieldLiteType* other) {
   MapField* down_other = down_cast<MapField*>(other);
-  std::swap(repeated_field_, down_other->repeated_field_);
+  std::swap(MapFieldBase::repeated_field_, down_other->repeated_field_);
   MapFieldLiteType::Swap(other);
-  std::swap(state_, down_other->state_);
+  std::swap(MapFieldBase::state_, down_other->state_);
 }
 
 template <typename Key, typename T,
@@ -171,7 +346,7 @@
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::SetEntryDescriptor(
     const Descriptor** descriptor) {
-  entry_descriptor_ = descriptor;
+  MapFieldBase::entry_descriptor_ = descriptor;
 }
 
 template <typename Key, typename T,
@@ -181,7 +356,7 @@
 void
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::SetAssignDescriptorCallback(void (*callback)()) {
-  assign_descriptor_callback_ = callback;
+  MapFieldBase::assign_descriptor_callback_ = callback;
 }
 
 template <typename Key, typename T,
@@ -211,17 +386,19 @@
 void
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::SyncRepeatedFieldWithMapNoLock() const {
-  if (repeated_field_ == NULL) {
-    if (arena_ == NULL) {
-      repeated_field_ = new RepeatedPtrField<Message>();
+  if (MapFieldBase::repeated_field_ == NULL) {
+    if (MapFieldBase::arena_ == NULL) {
+      MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>();
     } else {
-      repeated_field_ =
-          Arena::Create<RepeatedPtrField<Message> >(arena_, arena_);
+      MapFieldBase::repeated_field_ =
+          Arena::CreateMessage<RepeatedPtrField<Message> >(
+              MapFieldBase::arena_);
     }
   }
   const Map<Key, T>& map = GetInternalMap();
   RepeatedPtrField<EntryType>* repeated_field =
-      reinterpret_cast<RepeatedPtrField<EntryType>*>(repeated_field_);
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          MapFieldBase::repeated_field_);
 
   repeated_field->Clear();
 
@@ -229,7 +406,8 @@
        it != map.end(); ++it) {
     InitDefaultEntryOnce();
     GOOGLE_CHECK(default_entry_ != NULL);
-    EntryType* new_entry = down_cast<EntryType*>(default_entry_->New(arena_));
+    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;
@@ -245,7 +423,9 @@
          default_enum_value>::SyncMapWithRepeatedFieldNoLock() const {
   Map<Key, T>* map = const_cast<MapField*>(this)->MutableInternalMap();
   RepeatedPtrField<EntryType>* repeated_field =
-      reinterpret_cast<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) {
@@ -266,15 +446,15 @@
 MapField<Key, T, kKeyFieldType, kValueFieldType,
          default_enum_value>::SpaceUsedExcludingSelfNoLock() const {
   int size = 0;
-  if (repeated_field_ != NULL) {
-    size += repeated_field_->SpaceUsedExcludingSelf();
+  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 += KeyHandler::SpaceUsedInMap(it->first);
-    size += ValHandler::SpaceUsedInMap(it->second);
+    size += KeyTypeHandler::SpaceUsedInMap(it->first);
+    size += ValueTypeHandler::SpaceUsedInMap(it->second);
   }
   return size;
 }
@@ -288,10 +468,11 @@
          default_enum_value>::InitDefaultEntryOnce()
     const {
   if (default_entry_ == NULL) {
-    InitMetadataOnce();
-    GOOGLE_CHECK(*entry_descriptor_ != NULL);
+    MapFieldBase::InitMetadataOnce();
+    GOOGLE_CHECK(*MapFieldBase::entry_descriptor_ != NULL);
     default_entry_ = down_cast<const EntryType*>(
-        MessageFactory::generated_factory()->GetPrototype(*entry_descriptor_));
+        MessageFactory::generated_factory()->GetPrototype(
+            *MapFieldBase::entry_descriptor_));
   }
 }
 
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index 549ecc0..860dae5 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -45,7 +45,7 @@
           WireFormatLite::FieldType key_wire_type,
           WireFormatLite::FieldType value_wire_type,
           int default_enum_value = 0>
-class LIBPROTOBUF_EXPORT MapFieldLite {
+class MapFieldLite {
   // Define message type for internal repeated field.
   typedef MapEntryLite<Key, T, key_wire_type, value_wire_type,
                        default_enum_value> EntryType;
@@ -109,7 +109,7 @@
 MapFieldLite<Key, T, key_wire_type, value_wire_type,
              default_enum_value>::MapFieldLite(Arena* arena)
   : arena_(arena) {
-  map_ = Arena::Create<Map<Key, T> >(arena, arena);
+  map_ = Arena::CreateMessage<Map<Key, T> >(arena);
   SetDefaultEnumValue();
 }
 
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index 61344cb..2ff1d6b 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -34,6 +34,7 @@
 #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>
@@ -56,6 +57,7 @@
 
 class MapFieldBaseStub : public MapFieldBase {
  public:
+  typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
   MapFieldBaseStub() {}
   explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
@@ -73,6 +75,28 @@
   bool IsRepeatedClean() { return state_ != 1; }
   void SetMapDirty() { state_ = 0; }
   void SetRepeatedDirty() { state_ = 1; }
+  bool ContainsMapKey(const MapKey& map_key) const {
+    return false;
+  }
+  bool InsertMapValue(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 {
@@ -144,15 +168,17 @@
   // 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.data();
+  options.initial_block = &arena_block[0];
   options.initial_block_size = arena_block.size();
   Arena arena(options);
 
   {
-    NoHeapChecker no_heap;
+    // 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::Create<MapFieldType>(&arena, &arena, default_entry_);
+        Arena::CreateMessage<MapFieldType>(&arena, default_entry_);
 
     // Set content in map
     (*map_field->MutableMap())[100] = 101;
@@ -162,10 +188,12 @@
   }
 
   {
-    NoHeapChecker no_heap;
+    // 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::Create<MapFieldBaseStub>(&arena, &arena);
+        Arena::CreateMessage<MapFieldBaseStub>(&arena);
 
     // Trigger conversion to repeated field.
     EXPECT_TRUE(map_field->MutableRepeatedField() != NULL);
diff --git a/src/google/protobuf/map_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h
index 77b5336..66dedde 100644
--- a/src/google/protobuf/map_lite_test_util.h
+++ b/src/google/protobuf/map_lite_test_util.h
@@ -47,7 +47,7 @@
   // Set every field in the message to a default value.
   static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message);
 
-  // Modify all the map fields of the messsage (which should already have been
+  // Modify all the map fields of the message (which should already have been
   // initialized with SetMapFields()).
   static void ModifyMapFields(protobuf_unittest::TestMapLite* message);
 
diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto
index c69e8d9..0592dd7 100644
--- a/src/google/protobuf/map_lite_unittest.proto
+++ b/src/google/protobuf/map_lite_unittest.proto
@@ -34,6 +34,7 @@
 option optimize_for = LITE_RUNTIME;
 
 import "google/protobuf/unittest_lite.proto";
+import "google/protobuf/unittest_no_arena_lite.proto";
 
 package protobuf_unittest;
 
@@ -72,8 +73,12 @@
   map<int32   , float   > map_int32_float       = 11;
   map<int32   , double  > map_int32_double      = 12;
   map<bool    , bool    > map_bool_bool         = 13;
-  map<int32   , MapEnumLite> map_int32_enum     = 14;
-  map<int32   , ForeignMessageArenaLite> map_int32_foreign_message = 15;
+  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
@@ -81,10 +86,6 @@
   map<int32, TestRequiredLite> map_field = 1;
 }
 
-message TestEnumStartWithNonZeroMapLite {
-  map<int32, Proto2MapEnumStartWithNonZeroLite> map_field = 101;
-}
-
 message TestEnumMapLite {
   map<int32, Proto2MapEnumLite> known_map_field = 101;
   map<int32, Proto2MapEnumLite> unknown_map_field = 102;
@@ -112,10 +113,6 @@
   E_PROTO2_MAP_ENUM_EXTRA_LITE = 3;
 }
 
-enum Proto2MapEnumStartWithNonZeroLite {
-  PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE = 1;
-}
-
 enum MapEnumLite {
   MAP_ENUM_FOO_LITE = 0;
   MAP_ENUM_BAR_LITE = 1;
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
index 3d4af28..916cc54 100644
--- a/src/google/protobuf/map_proto2_unittest.proto
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -31,6 +31,8 @@
 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".
@@ -49,10 +51,6 @@
   E_PROTO2_MAP_ENUM_EXTRA = 3;
 }
 
-enum Proto2MapEnumStartWithNonZero {
-  PROTO2_NON_ZERO_MAP_ENUM_FOO = 1;
-}
-
 message TestEnumMap {
   map<int32, Proto2MapEnum> known_map_field = 101;
   map<int32, Proto2MapEnum> unknown_map_field = 102;
@@ -63,6 +61,6 @@
   map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
 }
 
-message TestEnumStartWithNonZeroMap {
-  map<int32, Proto2MapEnumStartWithNonZero> map_field = 101;
+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
index 88cba1f..451b02e 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -36,7 +36,9 @@
 #include <sstream>
 
 #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>
@@ -70,6 +72,7 @@
 using google::protobuf::unittest::ForeignMessage;
 using google::protobuf::unittest::TestAllTypes;
 using google::protobuf::unittest::TestMap;
+using google::protobuf::unittest::TestRecursiveMapMessage;
 
 namespace protobuf {
 namespace internal {
@@ -200,6 +203,21 @@
   EXPECT_DEATH(const_map_.at(0), "");
 }
 
+TEST_F(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_F(MapImplTest, CountNonExist) {
@@ -475,6 +493,23 @@
   EXPECT_EQ(value2, other.at(key2));
 }
 
+TEST_F(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());
+
+  EXPECT_EQ(2, new_map.size());
+  EXPECT_EQ(value1, new_map.at(key1));
+  EXPECT_EQ(value2, new_map.at(key2));
+}
+
 TEST_F(MapImplTest, Assigner) {
   int32 key1 = 0;
   int32 key2 = 1;
@@ -1140,6 +1175,19 @@
   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();
@@ -1147,7 +1195,7 @@
   mmf_int32_foreign_message.RemoveLast();
   EXPECT_EQ(10, message.map_int32_int32().size());
   EXPECT_EQ(10, message.map_int32_double().size());
-  EXPECT_EQ(10, message.map_string_string().size());
+  EXPECT_EQ(11, message.map_string_string().size());
   EXPECT_EQ(10, message.map_int32_foreign_message().size());
 
   // Test MutableRepeatedFieldRef::SwapElements()
@@ -1398,9 +1446,9 @@
 }
 
 TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) {
-  unittest::TestEnumStartWithNonZeroMap message;
-  EXPECT_EQ(unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO,
-            (*message.mutable_map_field())[0]);
+  unittest::TestEnumMap message;
+  EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO,
+            (*message.mutable_known_map_field())[0]);
 }
 
 TEST(GeneratedMapFieldTest, Clear) {
@@ -1526,12 +1574,28 @@
   google::protobuf::scoped_ptr<Message> message1;
   message1.reset(
       factory.GetPrototype(unittest::TestMap::descriptor())->New());
-
-  MapTestUtil::MapReflectionTester reflection_tester(
+  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);
 }
@@ -1547,10 +1611,41 @@
   message1.reset(
       factory.GetPrototype(unittest::TestMap::descriptor())->New());
 
-  MapTestUtil::MapReflectionTester reflection_tester(
+  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
@@ -1779,7 +1874,7 @@
 
 TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
   unittest::TestMap message;
-  MapTestUtil::MapReflectionTester reflection_tester(
+  MapReflectionTester reflection_tester(
     unittest::TestMap::descriptor());
   reflection_tester.SetMapFieldsViaReflection(&message);
 
@@ -1790,11 +1885,12 @@
   // Set every field to a unique value then go back and check all those
   // values.
   unittest::TestMap message;
-  MapTestUtil::MapReflectionTester reflection_tester(
+  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);
@@ -1848,15 +1944,16 @@
   MapTestUtil::SetMapFields(&message);
   MapTestUtil::ExpectMapFieldsSet(message);
 
-  MapTestUtil::MapReflectionTester reflection_tester(
+  MapReflectionTester reflection_tester(
       unittest::TestMap::descriptor());
   reflection_tester.ClearMapFieldsViaReflection(&message);
-  MapTestUtil::ExpectClear(message);
+  reflection_tester.ExpectClearViaReflection(message);
+  reflection_tester.ExpectClearViaReflectionIterator(&message);
 }
 
 TEST(GeneratedMapFieldReflectionTest, RemoveLast) {
   unittest::TestMap message;
-  MapTestUtil::MapReflectionTester reflection_tester(
+  MapReflectionTester reflection_tester(
       unittest::TestMap::descriptor());
 
   MapTestUtil::SetMapFields(&message);
@@ -1875,7 +1972,7 @@
 TEST(GeneratedMapFieldReflectionTest, ReleaseLast) {
   unittest::TestMap message;
   const Descriptor* descriptor = message.GetDescriptor();
-  MapTestUtil::MapReflectionTester reflection_tester(descriptor);
+  MapReflectionTester reflection_tester(descriptor);
 
   MapTestUtil::SetMapFields(&message);
 
@@ -1904,7 +2001,7 @@
 
 TEST(GeneratedMapFieldReflectionTest, SwapElements) {
   unittest::TestMap message;
-  MapTestUtil::MapReflectionTester reflection_tester(
+  MapReflectionTester reflection_tester(
     unittest::TestMap::descriptor());
 
   MapTestUtil::SetMapFields(&message);
@@ -1944,7 +2041,7 @@
 
 TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) {
   unittest::TestMap message;
-  MapTestUtil::MapReflectionTester reflection_tester(
+  MapReflectionTester reflection_tester(
     unittest::TestMap::descriptor());
   reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
 }
@@ -2000,24 +2097,35 @@
 
 TEST(GeneratedMapFieldReflectionTest, MapEntryClear) {
   unittest::TestMap message;
-  MapTestUtil::MapReflectionTester reflection_tester(
+  MapReflectionTester reflection_tester(
     unittest::TestMap::descriptor());
   reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
 }
 
 TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) {
-  unittest::TestEnumStartWithNonZeroMap message;
+  unittest::TestEnumMap message;
   const Descriptor* descriptor = message.GetDescriptor();
   const FieldDescriptor* field_descriptor =
-      descriptor->FindFieldByName("map_field");
+      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(1, sub_message->GetReflection()->GetEnumValue(*sub_message,
+  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 {
@@ -2025,6 +2133,7 @@
   const DescriptorPool* pool_;
   DynamicMessageFactory factory_;
   const Descriptor* map_descriptor_;
+  const Descriptor* recursive_map_descriptor_;
   const Message* map_prototype_;
 
   MapFieldInDynamicMessageTest()
@@ -2033,7 +2142,10 @@
   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_);
   }
 };
@@ -2042,20 +2154,20 @@
   // 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(map_prototype_->New());
-  MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_);
+  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, Map) {
+TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
   // Check that map fields work properly.
-  scoped_ptr<Message> message(map_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
 
   // Check set functions.
-  MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_);
-  reflection_tester.SetMapFieldsViaReflection(message.get());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
   reflection_tester.ExpectMapFieldsSetViaReflection(*message);
 }
 
@@ -2065,8 +2177,8 @@
   // 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(map_prototype_->New());
-  MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_);
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
 
   int initial_space_used = message->SpaceUsed();
 
@@ -2074,6 +2186,15 @@
   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) {
@@ -2258,20 +2379,42 @@
   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.data();
+  options.initial_block = &arena_block[0];
   options.initial_block_size = arena_block.size();
   Arena arena(options);
   string data;
   data.reserve(128 * 1024);
 
   {
-    NoHeapChecker no_heap;
+    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map.
+    // NoHeapChecker no_heap;
 
     unittest::TestArenaMap* from =
         Arena::CreateMessage<unittest::TestArenaMap>(&arena);
@@ -2305,6 +2448,22 @@
   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
index 1713e37..ae09464 100644
--- a/src/google/protobuf/map_test_util.cc
+++ b/src/google/protobuf/map_test_util.cc
@@ -209,7 +209,7 @@
   return result;
 }
 
-MapTestUtil::MapReflectionTester::MapReflectionTester(
+MapReflectionTester::MapReflectionTester(
     const Descriptor* base_descriptor)
   : base_descriptor_(base_descriptor) {
   const DescriptorPool* pool = base_descriptor->file()->pool();
@@ -329,14 +329,14 @@
 }
 
 // Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
-const FieldDescriptor* MapTestUtil::MapReflectionTester::F(const string& name) {
+const FieldDescriptor* MapReflectionTester::F(const string& name) {
   const FieldDescriptor* result = NULL;
   result = base_descriptor_->FindFieldByName(name);
   GOOGLE_CHECK(result != NULL);
   return result;
 }
 
-void MapTestUtil::MapReflectionTester::SetMapFieldsViaReflection(
+void MapReflectionTester::SetMapFieldsViaReflection(
     Message* message) {
   const Reflection* reflection = message->GetReflection();
   Message* sub_message = NULL;
@@ -555,7 +555,196 @@
       SetInt32(sub_foreign_message, foreign_c_, 1);
 }
 
-void MapTestUtil::MapReflectionTester::ClearMapFieldsViaReflection(
+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();
 
@@ -578,97 +767,103 @@
   reflection->ClearField(message, F("map_int32_foreign_message"));
 }
 
-void MapTestUtil::MapReflectionTester::ModifyMapFieldsViaReflection(
+void MapReflectionTester::ModifyMapFieldsViaReflection(
     Message* message) {
   const Reflection* reflection = message->GetReflection();
-  Message* sub_message;
+  MapValueRef map_val;
   Message* sub_foreign_message;
 
-  // Find out which one's key is 0.
-  int size = reflection->FieldSize(*message, F("map_int32_int32"));
-  int target = 0;
-  for (int i = 0; i < size; i++) {
-    const Message& temp_message = reflection
-      ->GetRepeatedMessage(*message, F("map_int32_int32"), i);
-    if (temp_message.GetReflection()
-          ->GetInt32(temp_message, map_int32_int32_key_) == 1) {
-      target = i;
-    }
-  }
+  // 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);
 
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int32_int32"), target);
-  sub_message->GetReflection()
-      ->SetInt32(sub_message, map_int32_int32_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int64_int64"), target);
-  sub_message->GetReflection()
-      ->SetInt64(sub_message, map_int64_int64_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_uint32_uint32"), target);
-  sub_message->GetReflection()
-      ->SetUInt32(sub_message, map_uint32_uint32_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_uint64_uint64"), target);
-  sub_message->GetReflection()
-      ->SetUInt64(sub_message, map_uint64_uint64_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_sint32_sint32"), target);
-  sub_message->GetReflection()
-      ->SetInt32(sub_message, map_sint32_sint32_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_sint64_sint64"), target);
-  sub_message->GetReflection()
-      ->SetInt64(sub_message, map_sint64_sint64_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_fixed32_fixed32"), target);
-  sub_message->GetReflection()
-      ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_fixed64_fixed64"), target);
-  sub_message->GetReflection()
-      ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_sfixed32_sfixed32"), target);
-  sub_message->GetReflection()
-      ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_sfixed64_sfixed64"), target);
-  sub_message->GetReflection()
-      ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 2);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int32_float"), target);
-  sub_message->GetReflection()
-      ->SetFloat(sub_message, map_int32_float_val_, 2.0);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int32_double"), target);
-  sub_message->GetReflection()
-      ->SetDouble(sub_message, map_int32_double_val_, 2.0);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_bool_bool"), target);
-  sub_message->GetReflection()
-      ->SetBool(sub_message, map_bool_bool_val_, false);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_string_string"), target);
-  sub_message->GetReflection()
-      ->SetString(sub_message, map_string_string_val_, "2");
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int32_bytes"), target);
-  sub_message->GetReflection()
-      ->SetString(sub_message, map_int32_bytes_val_, "2");
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int32_enum"), target);
-  sub_message->GetReflection()
-      ->SetEnum(sub_message, map_int32_enum_val_, map_enum_foo_);
-  sub_message = reflection
-      ->MutableRepeatedMessage(message, F("map_int32_foreign_message"), target);
-  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_, 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 MapTestUtil::MapReflectionTester::RemoveLastMapsViaReflection(
+void MapReflectionTester::RemoveLastMapsViaReflection(
     Message* message) {
   const Reflection* reflection = message->GetReflection();
 
@@ -681,7 +876,7 @@
   }
 }
 
-void MapTestUtil::MapReflectionTester::ReleaseLastMapsViaReflection(
+void MapReflectionTester::ReleaseLastMapsViaReflection(
     Message* message) {
   const Reflection* reflection = message->GetReflection();
 
@@ -699,7 +894,7 @@
   }
 }
 
-void MapTestUtil::MapReflectionTester::SwapMapsViaReflection(Message* message) {
+void MapReflectionTester::SwapMapsViaReflection(Message* message) {
   const Reflection* reflection = message->GetReflection();
   vector<const FieldDescriptor*> output;
   reflection->ListFields(*message, &output);
@@ -710,7 +905,7 @@
   }
 }
 
-void MapTestUtil::MapReflectionTester::
+void MapReflectionTester::
     MutableUnknownFieldsOfMapFieldsViaReflection(Message* message) {
   const Reflection* reflection = message->GetReflection();
   Message* sub_message = NULL;
@@ -768,11 +963,12 @@
               NULL);
 }
 
-void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection(
+void MapReflectionTester::ExpectMapFieldsSetViaReflection(
     const Message& message) {
   string scratch;
   const Reflection* reflection = message.GetReflection();
   const Message* sub_message;
+  MapKey map_key;
 
   // -----------------------------------------------------------------
 
@@ -799,6 +995,7 @@
     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(
@@ -806,6 +1003,10 @@
       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));
     }
   }
   {
@@ -813,6 +1014,7 @@
     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(
@@ -820,6 +1022,10 @@
       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));
     }
   }
   {
@@ -827,6 +1033,7 @@
     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(
@@ -834,6 +1041,10 @@
       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));
     }
   }
   {
@@ -848,6 +1059,10 @@
       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));
     }
   }
   {
@@ -862,6 +1077,10 @@
       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));
     }
   }
   {
@@ -876,6 +1095,10 @@
       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));
     }
   }
   {
@@ -890,6 +1113,10 @@
       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));
     }
   }
   {
@@ -904,6 +1131,10 @@
       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));
     }
   }
   {
@@ -918,6 +1149,10 @@
       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));
     }
   }
   {
@@ -932,6 +1167,10 @@
       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));
     }
   }
   {
@@ -946,6 +1185,10 @@
       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));
     }
   }
   {
@@ -960,6 +1203,10 @@
       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));
     }
   }
   {
@@ -974,6 +1221,10 @@
       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));
     }
   }
   {
@@ -988,6 +1239,10 @@
       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));
     }
   }
   {
@@ -1002,6 +1257,10 @@
       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));
     }
   }
   {
@@ -1016,6 +1275,10 @@
       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));
     }
   }
   {
@@ -1032,11 +1295,245 @@
       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 MapTestUtil::MapReflectionTester::ExpectClearViaReflection(
+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.
@@ -1059,7 +1556,46 @@
   EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
 }
 
-void MapTestUtil::MapReflectionTester::ExpectMapEntryClearViaReflection(
+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;
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
index f437e33..deaf0f4 100644
--- a/src/google/protobuf/map_test_util.h
+++ b/src/google/protobuf/map_test_util.h
@@ -49,7 +49,7 @@
   // Set every field in the message to a default value.
   static void SetMapFieldsInitialized(unittest::TestMap* message);
 
-  // Modify all the map fields of the messsage (which should already have been
+  // Modify all the map fields of the message (which should already have been
   // initialized with SetMapFields()).
   static void ModifyMapFields(unittest::TestMap* message);
 
@@ -83,71 +83,74 @@
   // 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);
+// 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 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 ExpectClearViaReflection(const Message& message);
-    void ExpectMapEntryClearViaReflection(Message* message);
+  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);
+ private:
+  const FieldDescriptor* F(const string& name);
 
-    const Descriptor* base_descriptor_;
+  const Descriptor* base_descriptor_;
 
-    const EnumValueDescriptor* map_enum_bar_;
-    const EnumValueDescriptor* map_enum_baz_;
-    const EnumValueDescriptor* map_enum_foo_;
+  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_;
-  };
+  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
diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h
index 5e7882a..b3ba4e0 100644
--- a/src/google/protobuf/map_test_util_impl.h
+++ b/src/google/protobuf/map_test_util_impl.h
@@ -31,6 +31,7 @@
 #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>
 
 
@@ -63,7 +64,7 @@
   template <typename MapMessage>
   static void SetMapFieldsInitialized(MapMessage* message);
 
-  // Modify all the map fields of the messsage (which should already have been
+  // 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);
@@ -167,8 +168,11 @@
   (*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;
@@ -184,8 +188,11 @@
   (*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>
@@ -329,8 +336,11 @@
   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));
@@ -345,8 +355,11 @@
   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));
@@ -361,8 +374,11 @@
   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>
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index 278b78a..f8ad758 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -54,22 +54,6 @@
   typedef FalseType type;
 };
 
-// In MapField, string and message are stored as pointer while others are stored
-// as object. However, google::protobuf::Map has unified api. Functions in this class
-// convert key/value to type wanted in api regardless how it's stored
-// internally.
-template <typename Type>
-class MapCommonTypeHandler {
- public:
-  static inline Type& Reference(Type* x) { return *x; }
-  static inline Type& Reference(Type& x) { return x; }
-  static inline const Type& Reference(const Type& x) { return x; }
-  static inline Type* Pointer(Type* x) { return x; }
-  static inline Type* Pointer(Type& x) { return &x; }
-  static inline const Type* Pointer(const Type* x) { return x; }
-  static inline const Type* Pointer(const Type& x) { return &x; }
-};
-
 // 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>
@@ -110,174 +94,29 @@
 class MapArenaMessageCreator<Type, false> {
  public:
   static inline Type* CreateMessage(Arena* arena) {
-    return new Type;
+    return Arena::Create<Type>(arena);
   }
 };
 
-// Handlers for key/value stored type in MapField. ==================
-
-// Handler for message
-template <typename Type>
-class MapCppTypeHandler : public MapCommonTypeHandler<Type> {
- public:
-  static const bool kIsStringOrMessage = true;
-  // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
-  // those already calculate in sizeof(MapField).
-  static int SpaceUsedInMapEntry(const Type* value) {
-    return value->SpaceUsed();
-  }
-  // Return bytes used by value in Map.
-  static int SpaceUsedInMap(const Type& value) { return value.SpaceUsed(); }
-  static inline void Clear(Type** value) {
-    if (*value != NULL) (*value)->Type::Clear();
-  }
-  static inline void ClearMaybeByDefaultEnum(Type** value,
-                                             int default_enum_value) {
-    if (*value != NULL) (*value)->Type::Clear();
-  }
-  static inline void Merge(const Type& from, Type** to) {
-    (*to)->MergeFrom(from);
-  }
-
-  static void Delete(const Type* ptr) { delete ptr; }
-
-  // Assign default value to given instance.
-  static inline void AssignDefaultValue(Type** value) {
-    *value = const_cast<Type*>(&Type::default_instance());
-  }
-  // Initialize value when constructing MapEntry
-  static inline void Initialize(Type** x, Arena* arena) { *x = NULL; }
-  // Same as above, but use default_enum_value to initialize enum type value.
-  static inline void InitializeMaybeByDefaultEnum(
-      Type** x, int default_enum_value, Arena* arena) {
-    *x = NULL;
-  }
-  // Initialize value for the first time mutable accessor is called.
-  static inline void EnsureMutable(Type** value, Arena* arena) {
-    if (*value == NULL) {
-      *value =
-          MapArenaMessageCreator<Type, Arena::is_arena_constructable<Type>::
-                                           type::value>::CreateMessage(arena);
-    }
-  }
-  // 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) {
-    return value != NULL ? *value : *default_value;
-  }
-  // Check if all required fields have values set.
-  static inline bool IsInitialized(Type* value) {
-    return value->IsInitialized();
-  }
-};
-
-// Handler for string.
-template <>
-class MapCppTypeHandler<string> : public MapCommonTypeHandler<string> {
- public:
-  static const bool kIsStringOrMessage = true;
-  static inline void Merge(const string& from, string** to) { **to = from; }
-  static inline void Clear(string** value) { (*value)->clear(); }
-  static inline void ClearMaybeByDefaultEnum(string** value, int default_enum) {
-    (*value)->clear();
-  }
-  static inline int SpaceUsedInMapEntry(const string* value) {
-    return sizeof(*value) + StringSpaceUsedExcludingSelf(*value);
-  }
-  static inline int SpaceUsedInMap(const string& value) {
-    return sizeof(value) + StringSpaceUsedExcludingSelf(value);
-  }
-  static void Delete(const string* ptr) {
-    if (ptr != &::google::protobuf::internal::GetEmptyString()) delete ptr;
-  }
-  static inline void AssignDefaultValue(string** value) {}
-  static inline void Initialize(string** value, Arena* arena) {
-    *value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString());
-    if (arena != NULL) arena->Own(*value);
-  }
-  static inline void InitializeMaybeByDefaultEnum(
-      string** value, int default_enum_value, Arena* arena) {
-    *value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString());
-    if (arena != NULL) arena->Own(*value);
-  }
-  static inline void EnsureMutable(string** value, Arena* arena) {
-    if (*value == &::google::protobuf::internal::GetEmptyString()) {
-      *value = Arena::Create<string>(arena);
-    }
-  }
-  static inline const string& DefaultIfNotInitialized(
-      const string* value,
-      const string* default_value) {
-    return value != default_value ? *value : *default_value;
-  }
-  static inline bool IsInitialized(string* value) { return true; }
-};
-
-// Base class for primitive type handlers.
-template <typename Type>
-class MapPrimitiveTypeHandler : public MapCommonTypeHandler<Type> {
- public:
-  static const bool kIsStringOrMessage = false;
-  static inline void Delete(const Type& x) {}
-  static inline void Merge(const Type& from, Type* to) { *to = from; }
-  static inline int SpaceUsedInMapEntry(const Type& value) { return 0; }
-  static inline int SpaceUsedInMap(const Type& value) { return sizeof(Type); }
-  static inline void AssignDefaultValue(Type* value) {}
-  static inline const Type& DefaultIfNotInitialized(
-      const Type& value, const Type& default_value) {
-    return value;
-  }
-  static inline bool IsInitialized(const Type& value) { return true; }
-};
-
-// Handlers for primitive types.
-#define PRIMITIVE_HANDLER(CType)                                              \
-  template <>                                                                 \
-  class MapCppTypeHandler<CType> : public MapPrimitiveTypeHandler<CType> {    \
-   public:                                                                    \
-    static inline void Clear(CType* value) { *value = 0; }                    \
-    static inline void ClearMaybeByDefaultEnum(CType* value,                  \
-                                               int default_enum_value) {      \
-      *value = static_cast<CType>(default_enum_value);                        \
-    }                                                                         \
-    static inline void Initialize(CType* value, Arena* arena) { *value = 0; } \
-    static inline void InitializeMaybeByDefaultEnum(CType* value,             \
-                                                    int default_enum_value,   \
-                                                    Arena* arena) {           \
-      *value = static_cast<CType>(default_enum_value);                        \
-    }                                                                         \
-    static inline void EnsureMutable(CType* value, Arena* arena) {}           \
-  };
-
-PRIMITIVE_HANDLER(int32 )
-PRIMITIVE_HANDLER(int64 )
-PRIMITIVE_HANDLER(uint32)
-PRIMITIVE_HANDLER(uint64)
-PRIMITIVE_HANDLER(double)
-PRIMITIVE_HANDLER(float )
-PRIMITIVE_HANDLER(bool  )
-
-#undef PRIMITIVE_HANDLER
-
 // Define constants for given wire field type
-template <WireFormatLite::FieldType field_type>
+template <WireFormatLite::FieldType field_type, typename Type>
 class MapWireFieldTypeTraits {};
 
-#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \
-  template <>                                                            \
-  class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType> {       \
-   public:                                                               \
-    typedef CType CppType;                                               \
-    static const bool kIsMessage = IsMessage;                            \
-    static const bool kIsEnum = IsEnum;                                  \
-    static const WireFormatLite::WireType kWireType =                    \
-        WireFormatLite::WIRETYPE_##WireFormatType;                       \
+#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 , MessageLite, LENGTH_DELIMITED, true, false)
-TYPE_TRAITS(STRING  , string ,  LENGTH_DELIMITED, false, false)
-TYPE_TRAITS(BYTES   , string ,  LENGTH_DELIMITED, false, false)
+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)
@@ -295,67 +134,168 @@
 
 #undef TYPE_TRAITS
 
-template <WireFormatLite::FieldType field_type>
-class MapWireFieldTypeHandler {
+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<field_type>::CppType CppType;
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+                                          Type>::TypeOnMemory TypeOnMemory;
   // Corresponding wire type for field type.
   static const WireFormatLite::WireType kWireType =
-      MapWireFieldTypeTraits<field_type>::kWireType;
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType;
   // Whether wire type is for message.
-  static const bool kIsMessage = MapWireFieldTypeTraits<field_type>::kIsMessage;
+  static const bool kIsMessage =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage;
   // Whether wire type is for enum.
-  static const bool kIsEnum = MapWireFieldTypeTraits<field_type>::kIsEnum;
+  static const bool kIsEnum =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsEnum;
 
   // Functions used in parsing and serialization. ===================
-  template <typename ValueType>
-  static inline int ByteSize(const ValueType& value);
-  template <typename ValueType>
-  static inline int GetCachedSize(const ValueType& value);
-  template <typename ValueType>
-  static inline bool Read(io::CodedInputStream* input, ValueType* value);
-  static inline void Write(int field, const CppType& value,
+  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 CppType& value,
+  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);
 };
 
-template <>
-template <typename ValueType>
-inline int MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::ByteSize(
-    const ValueType& 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 BYTE_SIZE(FieldType, DeclaredType)                             \
-  template <>                                                          \
-  template <typename ValueType>                                        \
-  inline int                                                           \
-  MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::ByteSize( \
-      const ValueType& value) {                                        \
-    return WireFormatLite::DeclaredType##Size(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);                          \
   }
 
-BYTE_SIZE(STRING, String)
-BYTE_SIZE(BYTES , Bytes)
-BYTE_SIZE(INT64 , Int64)
-BYTE_SIZE(UINT64, UInt64)
-BYTE_SIZE(INT32 , Int32)
-BYTE_SIZE(UINT32, UInt32)
-BYTE_SIZE(SINT64, SInt64)
-BYTE_SIZE(SINT32, SInt32)
-BYTE_SIZE(ENUM  , Enum)
+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 BYTE_SIZE
+#undef GOOGLE_PROTOBUF_BYTE_SIZE
 
-#define FIXED_BYTE_SIZE(FieldType, DeclaredType)                       \
-  template <>                                                          \
-  template <typename ValueType>                                        \
-  inline int                                                           \
-  MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::ByteSize( \
-      const ValueType& value) {                                        \
-    return WireFormatLite::k##DeclaredType##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)
@@ -368,20 +308,19 @@
 
 #undef FIXED_BYTE_SIZE
 
-template <>
-template <typename ValueType>
-inline int MapWireFieldTypeHandler<
-    WireFormatLite::TYPE_MESSAGE>::GetCachedSize(const ValueType& value) {
+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 <>                                                               \
-  template <typename ValueType>                                             \
-  inline int                                                                \
-  MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::GetCachedSize( \
-      const ValueType& value) {                                             \
-    return WireFormatLite::DeclaredType##Size(value);                       \
+#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)
@@ -396,13 +335,12 @@
 
 #undef GET_CACHED_SIZE
 
-#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType)                      \
-  template <>                                                               \
-  template <typename ValueType>                                             \
-  inline int                                                                \
-  MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::GetCachedSize( \
-      const ValueType& value) {                                             \
-    return WireFormatLite::k##DeclaredType##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)
@@ -415,30 +353,31 @@
 
 #undef GET_FIXED_CACHED_SIZE
 
-template <>
-inline void MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::Write(
-    int field, const MessageLite& value, io::CodedOutputStream* output) {
+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 <>
+template <typename Type>
 inline uint8*
-MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::WriteToArray(
-    int field, const MessageLite& value, uint8* output) {
+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 <>                                                                  \
-  inline void                                                                  \
-  MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::Write(            \
-      int field, const CppType& value, io::CodedOutputStream* output) {        \
+  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 <>                                                                  \
+  template <typename Type>                                                     \
   inline uint8*                                                                \
-  MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::WriteToArray(     \
-      int field, const CppType& value, uint8* output) {                        \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::WriteToArray(        \
+      int field, const MapEntryAccessorType& value, uint8* output) {           \
     return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
   }
 
@@ -461,35 +400,31 @@
 
 #undef WRITE_METHOD
 
-template <>
-template <typename ValueType>
-inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::Read(
-    io::CodedInputStream* input, ValueType* value) {
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
   return WireFormatLite::ReadMessageNoVirtual(input, value);
 }
 
-template <>
-template <typename ValueType>
-inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_STRING>::Read(
-    io::CodedInputStream* input, ValueType* value) {
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
   return WireFormatLite::ReadString(input, value);
 }
 
-template <>
-template <typename ValueType>
-inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_BYTES>::Read(
-    io::CodedInputStream* input, ValueType* 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 <>                                                                  \
-  template <typename ValueType>                                                \
-  inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::Read( \
-      io::CodedInputStream* input, ValueType* value) {                         \
-    return WireFormatLite::ReadPrimitive<CppType,                              \
-                                         WireFormatLite::TYPE_##FieldType>(    \
-        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)
@@ -509,6 +444,282 @@
 
 #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
 
diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto
index 830f672..aea1e8c 100644
--- a/src/google/protobuf/map_unittest.proto
+++ b/src/google/protobuf/map_unittest.proto
@@ -33,6 +33,7 @@
 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.
@@ -58,10 +59,11 @@
   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 {
-  optional TestMap test_map = 1;
+  TestMap test_map = 1;
 }
 
 message TestMessageMap {
@@ -100,6 +102,28 @@
   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;
+  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 f58be84..032748b 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -38,12 +38,15 @@
 
 #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>
@@ -256,6 +259,22 @@
   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
 
@@ -465,10 +484,33 @@
 }  // namespace internal
 
 namespace internal {
-// Macro defined in repeated_field.h. We can only define the Message-specific
-// GenericTypeHandler specializations here because we depend on Message, which
-// is not part of proto2-lite hence is not available in repeated_field.h.
-DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(Message);
+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
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 6e1929e..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;
 //   }
@@ -134,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
 }
 
 
@@ -229,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----------------------------------------------
@@ -719,6 +735,14 @@
                               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
@@ -863,11 +887,20 @@
   //   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
@@ -882,6 +915,8 @@
   // "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,
@@ -897,14 +932,73 @@
   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);
 };
 
@@ -1020,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<>
@@ -1038,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>
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 63be0e9..5bd8bcf 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -35,7 +35,9 @@
 
 #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>
@@ -98,27 +100,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);
@@ -127,26 +121,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();
@@ -337,7 +332,7 @@
 
 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;
@@ -353,5 +348,18 @@
   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);
+}
+}  // namespace internal
+
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index eab61c1..4c16f4c 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -238,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 ebfb432..2d4780f 100644
--- a/src/google/protobuf/message_unittest.cc
+++ b/src/google/protobuf/message_unittest.cc
@@ -45,13 +45,15 @@
 #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/testing/googletest.h>
 #include <gtest/gtest.h>
@@ -205,6 +207,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) {
diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h
index 30b2a6e..219645d 100644
--- a/src/google/protobuf/metadata.h
+++ b/src/google/protobuf/metadata.h
@@ -56,7 +56,7 @@
 // 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 {
+class InternalMetadataWithArena {
  public:
   InternalMetadataWithArena() : ptr_(NULL) {}
   explicit InternalMetadataWithArena(Arena* arena)
@@ -69,8 +69,7 @@
     ptr_ = NULL;
   }
 
-  inline const UnknownFieldSet& unknown_fields() const
-      GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE const UnknownFieldSet& unknown_fields() const {
     if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
       return PtrValue<Container>()->unknown_fields_;
     } else {
@@ -78,7 +77,7 @@
     }
   }
 
-  inline UnknownFieldSet* mutable_unknown_fields() GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE UnknownFieldSet* mutable_unknown_fields() {
     if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) {
       return &PtrValue<Container>()->unknown_fields_;
     } else {
@@ -86,7 +85,7 @@
     }
   }
 
-  inline Arena* arena() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE Arena* arena() const {
     if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
       return PtrValue<Container>()->arena_;
     } else {
@@ -94,11 +93,11 @@
     }
   }
 
-  inline bool have_unknown_fields() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool have_unknown_fields() const {
     return PtrTag() == kTagContainer;
   }
 
-  inline void Swap(InternalMetadataWithArena* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  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
@@ -110,7 +109,7 @@
     }
   }
 
-  inline void* raw_arena_ptr() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* raw_arena_ptr() const {
     return ptr_;
   }
 
@@ -128,7 +127,7 @@
   static const intptr_t kPtrValueMask = ~kPtrTagMask;
 
   // Accessors for pointer tag and pointer value.
-  inline int PtrTag() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE {
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE int PtrTag() const {
     return reinterpret_cast<intptr_t>(ptr_) & kPtrTagMask;
   }
 
@@ -143,7 +142,7 @@
     Arena* arena_;
   };
 
-  UnknownFieldSet* mutable_unknown_fields_slow() GOOGLE_ATTRIBUTE_NOINLINE {
+  GOOGLE_ATTRIBUTE_NOINLINE UnknownFieldSet* mutable_unknown_fields_slow() {
     Arena* my_arena = arena();
     Container* container = Arena::Create<Container>(my_arena);
     ptr_ = reinterpret_cast<void*>(
diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc
index 4b7b31d..bc41bee 100644
--- a/src/google/protobuf/no_field_presence_test.cc
+++ b/src/google/protobuf/no_field_presence_test.cc
@@ -341,6 +341,46 @@
   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;
diff --git a/src/google/protobuf/preserve_unknown_enum_test.cc b/src/google/protobuf/preserve_unknown_enum_test.cc
index 9f8703a..1673e8a 100644
--- a/src/google/protobuf/preserve_unknown_enum_test.cc
+++ b/src/google/protobuf/preserve_unknown_enum_test.cc
@@ -246,8 +246,6 @@
   protobuf_unittest::TestAllTypes message;  // proto2 message
   const google::protobuf::Reflection* r = message.GetReflection();
   const google::protobuf::Descriptor* d = message.GetDescriptor();
-  const google::protobuf::FieldDescriptor* singular_field =
-      d->FindFieldByName("optional_nested_enum");
   const google::protobuf::FieldDescriptor* repeated_field =
       d->FindFieldByName("repeated_nested_enum");
   // Add one element to the repeated field so that we can test
@@ -258,6 +256,8 @@
   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({
diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc
index c3b5996..2838e0f 100644
--- a/src/google/protobuf/proto3_arena_unittest.cc
+++ b/src/google/protobuf/proto3_arena_unittest.cc
@@ -119,7 +119,7 @@
 // proto3 and expect the arena support to be fully tested in proto2 unittests
 // because proto3 shares most code with proto2.
 
-TEST(ArenaTest, Parsing) {
+TEST(Proto3ArenaTest, Parsing) {
   TestAllTypes original;
   SetAllFields(&original);
 
@@ -129,7 +129,7 @@
   ExpectAllFieldsSet(*arena_message);
 }
 
-TEST(ArenaTest, UnknownFields) {
+TEST(Proto3ArenaTest, UnknownFields) {
   TestAllTypes original;
   SetAllFields(&original);
 
@@ -150,7 +150,7 @@
       arena_message->GetReflection()->GetUnknownFields(*arena_message).empty());
 }
 
-TEST(ArenaTest, Swap) {
+TEST(Proto3ArenaTest, Swap) {
   Arena arena1;
   Arena arena2;
 
@@ -162,7 +162,7 @@
   EXPECT_EQ(&arena2, arena2_message->GetArena());
 }
 
-TEST(ArenaTest, SetAllocatedMessage) {
+TEST(Proto3ArenaTest, SetAllocatedMessage) {
   Arena arena;
   TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
   TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
@@ -171,7 +171,7 @@
   EXPECT_EQ(118, arena_message->optional_nested_message().bb());
 }
 
-TEST(ArenaTest, ReleaseMessage) {
+TEST(Proto3ArenaTest, ReleaseMessage) {
   Arena arena;
   TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
   arena_message->mutable_optional_nested_message()->set_bb(118);
@@ -180,6 +180,30 @@
   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/proto_cast.h b/src/google/protobuf/proto_cast.h
deleted file mode 100644
index e25c219..0000000
--- a/src/google/protobuf/proto_cast.h
+++ /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.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
-#define GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
-
-#include <string>
-
-#include <google/protobuf/stubs/common.h>
-
-// proto_cast<> is used to simulate over-the-wire conversion of one
-// proto message into another.  This is primarily useful for unit tests
-// which validate the version-compatibility semantics of protobufs.
-// Usage is similar to C++-style typecasts:
-//
-// OldMessage old_message = /*...*/;
-// NewMessage new_message = proto_cast<NewMessage>(old_message);
-namespace google {
-template<typename NewProto,
-         typename OldProto>
-NewProto proto_cast(const OldProto& old_proto) {
-  string wire_format;
-  GOOGLE_CHECK(old_proto.SerializeToString(&wire_format));
-
-  NewProto new_proto;
-  GOOGLE_CHECK(new_proto.ParseFromString(wire_format));
-  return new_proto;
-}
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
diff --git a/src/google/protobuf/proto_cast_test.cc b/src/google/protobuf/proto_cast_test.cc
deleted file mode 100644
index eb101eb..0000000
--- a/src/google/protobuf/proto_cast_test.cc
+++ /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.
-
-#include <google/protobuf/util/proto_cast.h>
-
-#include <google/protobuf/util/unknown_enum_test.pb.h>
-#include <gtest/gtest.h>
-#include <google/protobuf/testing/gmock.h>
-
-namespace google {
-using google::protobuf::util::UpRevision;
-using google::protobuf::util::DownRevision;
-
-namespace {
-
-TEST(ProtoCastTest, V2KnownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NONDEFAULT_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value());
-}
-
-TEST(ProtoCastTest, V2UnknownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NEW_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::DEFAULT_VALUE, receiver.value());
-}
-
-}  // namespace
-}  // namespace google
diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h
index 03c761c..671aafd 100755
--- a/src/google/protobuf/reflection.h
+++ b/src/google/protobuf/reflection.h
@@ -39,6 +39,7 @@
 #endif
 
 #include <google/protobuf/message.h>
+#include <google/protobuf/generated_enum_util.h>
 
 namespace google {
 namespace protobuf {
@@ -552,7 +553,7 @@
 
 template<typename T>
 struct RefTypeTraits<
-    T, typename internal::enable_if<internal::is_same<string, T>::value>::type> {
+    T, typename internal::enable_if< ::google::protobuf::internal::is_same<string, T>::value>::type> {
   typedef RepeatedFieldRefIterator<T> iterator;
   typedef RepeatedFieldAccessor AccessorType;
   typedef string AccessorValueType;
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 e5aedad..949e0a2 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 {
@@ -53,13 +54,17 @@
   Arena* arena = GetArenaNoVirtual();
   new_size = max(kMinRepeatedFieldAllocationSize,
                  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]);
+        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));
+            kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size));
   }
   total_size_ = new_size;
   if (old_rep && old_rep->allocated_size > 0) {
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index f5f5d3f..5447fa4 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -54,6 +54,7 @@
 #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>
@@ -207,10 +208,19 @@
   // sizeof(*this)
   int SpaceUsedExcludingSelf() const;
 
-  // Remove the element referenced by position.
+  // 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);
 
-  // Remove the elements in the range [first, last).
+  // 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.
@@ -361,7 +371,7 @@
 
   // 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);
@@ -408,7 +418,7 @@
   const typename TypeHandler::Type* const* data() const;
 
   template <typename TypeHandler>
-  inline void Swap(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(RepeatedPtrFieldBase* other);
 
   void SwapElements(int index1, int index2);
 
@@ -458,22 +468,20 @@
   void AddAllocatedInternal(typename TypeHandler::Type* value,
                             google::protobuf::internal::false_type);
 
-  template <typename TypeHandler>
+  template <typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE
   void AddAllocatedSlowWithCopy(typename TypeHandler::Type* value,
                                 Arena* value_arena,
-                                Arena* my_arena)
-      GOOGLE_ATTRIBUTE_NOINLINE;
-  template <typename TypeHandler>
-  void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value)
-      GOOGLE_ATTRIBUTE_NOINLINE;
+                                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>
-  inline void SwapFallback(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_NOINLINE;
+  template<typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE
+  void SwapFallback(RepeatedPtrFieldBase* other);
 
   inline Arena* GetArenaNoVirtual() const {
     return arena_;
@@ -542,20 +550,10 @@
   }
   // 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. Note that the GOOGLE_ATTRIBUTE_NOINLINE macro
-  // requires the 'inline' storage class here, which is somewhat confusing, but
-  // the compiler does the right thing.
-  static inline GenericType* NewFromPrototype(const GenericType* prototype,
-                                              ::google::protobuf::Arena* arena = NULL)
-    GOOGLE_ATTRIBUTE_NOINLINE {
-    return New(arena);
-  }
-  static inline void Delete(GenericType* value, Arena* arena)
-    GOOGLE_ATTRIBUTE_NOINLINE {
-    if (arena == NULL) {
-      delete value;
-    }
-  }
+  // 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);
   }
@@ -564,10 +562,8 @@
   }
 
   static inline void Clear(GenericType* value) { value->Clear(); }
-  static inline void Merge(const GenericType& from, GenericType* to)
-      GOOGLE_ATTRIBUTE_NOINLINE {
-    to->MergeFrom(from);
-  }
+  GOOGLE_ATTRIBUTE_NOINLINE static void Merge(const GenericType& from,
+                                       GenericType* to);
   static inline int SpaceUsed(const GenericType& value) {
     return value.SpaceUsed();
   }
@@ -576,36 +572,44 @@
   }
 };
 
-// Macros for specializing GenericTypeHandler for base proto types, these are
-// are defined here, to allow inlining them at their callsites.
-#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Inline, TypeName)          \
-    template<> \
-    Inline TypeName* GenericTypeHandler<TypeName>::NewFromPrototype(           \
-        const TypeName* prototype, google::protobuf::Arena* arena) {                     \
-      return prototype->New(arena);                                            \
-    }                                                                          \
-    template<> \
-    Inline google::protobuf::Arena* GenericTypeHandler<TypeName>::GetArena(              \
-        TypeName* value) {                                                     \
-      return value->GetArena();                                                \
-    }                                                                          \
-    template<>                                                                 \
-    Inline void* GenericTypeHandler<TypeName>::GetMaybeArenaPointer(           \
-        TypeName* value) {                                                     \
-      return value->GetMaybeArenaPointer();                                    \
-    }
-#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(TypeName)         \
-    DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(, TypeName)
-
-// Implements GenericTypeHandler specialization required by RepeatedPtrFields
-// to work with MessageLite type.
-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);
 }
 
-DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(inline, MessageLite);
+// 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);
 
 // Declarations of the specialization as we cannot define them here, as the
 // header that defines ProtocolMessage depends on types defined in this header.
@@ -623,10 +627,10 @@
 // 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);
+DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message)
 
 
-#undef DECLARE_SPECIALIZATIONS_FOR_BASE_CLASSES
+#undef DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES
 
 template <>
 inline const MessageLite& GenericTypeHandler<MessageLite>::default_instance() {
@@ -654,7 +658,8 @@
 //   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;
@@ -669,7 +674,7 @@
   static inline ::google::protobuf::Arena* GetArena(string*) {
     return NULL;
   }
-  static inline void* GetMaybeArenaPointer(string* value) {
+  static inline void* GetMaybeArenaPointer(string* /* value */) {
     return NULL;
   }
   static inline void Delete(string* value, Arena* arena) {
@@ -687,7 +692,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);
   }
 };
 
@@ -889,10 +894,19 @@
   // so will trigger a GOOGLE_DCHECK-failure.
   Element* ReleaseCleared();
 
-  // Remove the element referenced by position.
+  // 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.
@@ -1132,7 +1146,9 @@
 inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
     const_iterator first, const_iterator last) {
   size_type first_offset = first - cbegin();
-  Truncate(std::copy(last, cend(), begin() + first_offset) - cbegin());
+  if (first != last) {
+    Truncate(std::copy(last, cend(), begin() + first_offset) - cbegin());
+  }
   return begin() + first_offset;
 }
 
@@ -1226,15 +1242,20 @@
   Arena* arena = GetArenaNoVirtual();
   new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
                  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]);
+        new char[kRepHeaderSize + sizeof(Element) * new_size]);
   } else {
     rep_ = reinterpret_cast<Rep*>(
             ::google::protobuf::Arena::CreateArray<char>(arena,
-                kRepHeaderSize + sizeof(Element)*new_size));
+                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
@@ -1253,15 +1274,17 @@
   if (current_size_ > 0) {
     MoveArray(rep_->elements, old_rep->elements, current_size_);
   }
-  // Likewise, we need to invoke destructors on the old array. If Element has no
-  // destructor, this loop will disappear.
-  e = &old_rep->elements[0];
-  limit = &old_rep->elements[current_size_];
-  for (; e < limit; e++) {
-    e->Element::~Element();
-  }
-  if (arena == NULL) {
-    delete[] reinterpret_cast<char*>(old_rep);
+  if (old_rep) {
+    // Likewise, we need to invoke destructors on the old array. If Element has
+    // no destructor, this loop will disappear.
+    e = &old_rep->elements[0];
+    limit = &old_rep->elements[old_total_size];
+    for (; e < limit; e++) {
+      e->Element::~Element();
+    }
+    if (arena == NULL) {
+      delete[] reinterpret_cast<char*>(old_rep);
+    }
   }
 }
 
@@ -1344,7 +1367,7 @@
 }
 
 template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) {
+void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) {
   GOOGLE_DCHECK(other->GetArenaNoVirtual() != GetArenaNoVirtual());
 
   // Copy semantics in this case. We try to improve efficiency by placing the
@@ -1418,7 +1441,7 @@
   const int n = current_size_;
   GOOGLE_DCHECK_GE(n, 0);
   if (n > 0) {
-    void* const* elements = raw_data();
+    void* const* elements = rep_->elements;
     int i = 0;
     do {
       TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 66e7452..b45664b 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>
@@ -456,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.
@@ -1407,7 +1430,6 @@
     std::copy(nested_ptrs.begin(), nested_ptrs.end(),
               RepeatedFieldBackInserter(
                   protobuffer.mutable_repeated_nested_message()));
-
   }
 
   virtual void TearDown() {
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..f2eb7ae
--- /dev/null
+++ b/src/google/protobuf/source_context.pb.cc
@@ -0,0 +1,388 @@
+// 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() {
+  file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool SourceContext::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SourceContext* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceContext>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void SourceContext::MergeFrom(const SourceContext& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SourceContext::CopyFrom(const SourceContext& from) {
+  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() {
+  
+  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..02e1146
--- /dev/null
+++ b/src/google/protobuf/source_context.pb.h
@@ -0,0 +1,185 @@
+// 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() {
+  
+  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..e020597
--- /dev/null
+++ b/src/google/protobuf/struct.pb.cc
@@ -0,0 +1,1470 @@
+// 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\000BN\n\023com.google.prot"
+    "obufB\013StructProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Pr"
+    "otobuf.WellKnownTypesb\006proto3", 589);
+  ::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() {
+  fields_.Clear();
+}
+
+bool Struct::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Struct* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Struct>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Struct::MergeFrom(const Struct& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  fields_.MergeFrom(from.fields_);
+}
+
+void Struct::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Struct::CopyFrom(const Struct& from) {
+  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() {
+  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() {
+  clear_kind();
+}
+
+bool Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Value>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Value::MergeFrom(const Value& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Value::CopyFrom(const Value& from) {
+  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() {
+  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() {
+  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() {
+  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() {
+  values_.Clear();
+}
+
+bool ListValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ListValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ListValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void ListValue::MergeFrom(const ListValue& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  values_.MergeFrom(from.values_);
+}
+
+void ListValue::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ListValue::CopyFrom(const ListValue& from) {
+  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..0527c81
--- /dev/null
+++ b/src/google/protobuf/struct.pb.h
@@ -0,0 +1,766 @@
+// 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() {
+  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() {
+  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() {
+  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
index 9f27eb4..8562e2c 100644
--- a/src/google/protobuf/struct.proto
+++ b/src/google/protobuf/struct.proto
@@ -27,14 +27,17 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (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 java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "StructProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 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
@@ -43,6 +46,8 @@
 // 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 {
   // Map of dynamically typed values.
   map<string, Value> fields = 1;
@@ -52,7 +57,10 @@
 // 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;
@@ -69,14 +77,18 @@
   }
 }
 
-// `NullValue` is a singleton enumeration to represent the null
-// value for the `Value` type union.
+// `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/atomicops.h b/src/google/protobuf/stubs/atomicops.h
index 36c1ec9..cb93227 100644
--- a/src/google/protobuf/stubs/atomicops.h
+++ b/src/google/protobuf/stubs/atomicops.h
@@ -56,6 +56,7 @@
 // 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 {
@@ -75,7 +76,7 @@
 #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
@@ -172,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)
@@ -182,7 +183,7 @@
 #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
@@ -191,7 +192,7 @@
 
 // AIX
 #elif defined(GOOGLE_PROTOBUF_OS_AIX)
-#include <google/protobuf/stubs/atomicops_internals_aix.h>
+#include <google/protobuf/stubs/atomicops_internals_power.h>
 
 // Apple.
 #elif defined(GOOGLE_PROTOBUF_OS_APPLE)
@@ -207,10 +208,10 @@
 #include <google/protobuf/stubs/atomicops_internals_arm64_gcc.h>
 #elif defined(GOOGLE_PROTOBUF_ARCH_ARM_QNX)
 #include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
-#elif defined(GOOGLE_PROTOBUF_ARCH_TILE)
-#include <google/protobuf/stubs/atomicops_internals_tile_gcc.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 (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
@@ -219,15 +220,15 @@
 #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_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_aix.h b/src/google/protobuf/stubs/atomicops_internals_power.h
similarity index 100%
rename from src/google/protobuf/stubs/atomicops_internals_aix.h
rename to src/google/protobuf/stubs/atomicops_internals_power.h
diff --git a/src/google/protobuf/stubs/atomicops_internals_tile_gcc.h b/src/google/protobuf/stubs/atomicops_internals_tile_gcc.h
deleted file mode 100644
index 796d742..0000000
--- a/src/google/protobuf/stubs/atomicops_internals_tile_gcc.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TILE_GCC_H_
-#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TILE_GCC_H_
-
-namespace google {
-namespace protobuf {
-namespace internal {
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-    asm volatile ("st4 %0, %1"
-                  : "=r" (*ptr)
-                  : "m" (value));
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-    Atomic32 dest;
-    asm volatile ("ld4s %0, %1"
-                  : "=r" (dest)
-                  : "m" (*ptr));
-    return dest;
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-    asm volatile ("st %0, %1"
-                  : "=r" (*ptr)
-                  : "m" (value));
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-    Atomic64 dest;
-    asm volatile ("ld %0, %1"
-                  : "=r" (dest)
-                  : "m" (*ptr));
-    return dest;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-    return NoBarrier_Load(ptr);
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-    NoBarrier_Store(ptr, value);
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-    Atomic64 tmp;
-    asm volatile ("mtspr CMPEXCH_VALUE, %3\n\t"
-                  "cmpexch %0, %1, %2"
-                  : "=r" (tmp), "=m" (*ptr)
-                  : "r" (new_value), "r" (old_value));
-    return tmp;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-    Atomic64 old_value;
-    asm volatile ("exch %0, %1, %2"
-                  : "=r" (old_value), "=m" (*ptr)
-                  : "r" (new_value));
-    return old_value;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 value) {
-    Atomic64 dest;
-    asm volatile ("fetchadd %0, %1, %2"
-                  : "=r" (dest), "=m" (*ptr)
-                  : "r" (value));
-    return *ptr;
-}
-
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
-
-#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TILE_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
index cccf65a..be65284 100644
--- a/src/google/protobuf/stubs/casts.h
+++ b/src/google/protobuf/stubs/casts.h
@@ -111,12 +111,22 @@
   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
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
index 54e00cc..54dbafa 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -32,12 +32,15 @@
 
 #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"
-
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN  // We only need minimal includes
 #include <windows.h>
@@ -47,6 +50,9 @@
 #else
 #error "No suitable threading library available."
 #endif
+#if defined(__ANDROID__)
+#include <android/log.h>
+#endif
 
 namespace google {
 namespace protobuf {
@@ -103,7 +109,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 +156,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 +191,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,11 +228,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 c3f735a..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
@@ -151,1037 +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_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))
-#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
-#endif
-#endif
-
-#ifndef GOOGLE_PREDICT_FALSE
-#ifdef __GNUC__
-// Provided at least since GCC 3.0.
-#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(!!(x), 1))
-#else
-#define GOOGLE_PREDICT_FALSE
-#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
-
-#define GOOGLE_GUARDED_BY(x)
-#define GOOGLE_FALLTHROUGH_INTENDED
-#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
-
-// ===================================================================
-// 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
-#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.
-
-// ===================================================================
-// 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;
-
-// ===================================================================
-// 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);
-  LogMessage& operator<<(void* 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) \
-  ::google::protobuf::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 5f458e9..25bae9b 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -39,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.
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
index 82d5052..5833432 100755
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -37,12 +37,127 @@
 
 #include <string.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/pbconfig.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
+#  undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+#  undef GOOGLE_PROTOBUF_HAVE_HASH_SET
+# 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
+# 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)
-#include GOOGLE_PROTOBUF_HASH_MAP_H
-#include GOOGLE_PROTOBUF_HASH_SET_H
 #else
 #define GOOGLE_PROTOBUF_MISSING_HASH
 #include <map>
@@ -53,6 +168,7 @@
 namespace protobuf {
 
 #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.
@@ -91,10 +207,13 @@
           typename HashFcn = hash<Key>,
           typename EqualKey = std::equal_to<Key>,
           typename Alloc = std::allocator< std::pair<const Key, Data> > >
-class hash_map : public std::map<Key, Data, HashFcn, EqualKey, Alloc> {
+class hash_map : public std::map<Key, Data, HashFcn, Alloc> {
+  typedef std::map<Key, Data, HashFcn, Alloc> BaseClass;
+
  public:
-  hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(),
-           const Alloc& = Alloc()) {}
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(),
+           const Alloc& d = Alloc()) : BaseClass(b, d) {}
 };
 
 template <typename Key,
@@ -108,7 +227,7 @@
 #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
 
 template <typename Key>
-struct hash : public GOOGLE_PROTOBUF_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
@@ -122,8 +241,7 @@
 
 template <>
 struct hash<const char*>
-    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash_compare<
-        const char*, CstringLess> {};
+    : public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
 
 template <typename Key, typename Data,
           typename HashFcn = hash<Key>,
@@ -132,9 +250,13 @@
 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, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(),
-           const Alloc& = Alloc()) {}
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(),
+           const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
 };
 
 template <typename Key, typename HashFcn = hash<Key>,
@@ -172,6 +294,13 @@
   }
 };
 
+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>,
@@ -179,9 +308,13 @@
 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, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(),
-           const Alloc& = Alloc()) {}
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(),
+           const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
 };
 
 template <typename Key, typename HashFcn = hash<Key>,
@@ -193,7 +326,6 @@
   hash_set(int = 0) {}
 };
 
-#undef GOOGLE_PROTOBUF_MISSING_HASH
 #endif  // !GOOGLE_PROTOBUF_MISSING_HASH
 
 template <>
@@ -204,7 +336,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;
   }
 };
@@ -222,7 +354,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..d80c64f
--- /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 <iostream>  // 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..3108db8
--- /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 GOOGLE_LOG_IF(INFO, 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/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..3a1ef8a
--- /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) ? value : -value;
+  }
+
+  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 0ab993f..22b3572 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"
 
@@ -52,9 +50,6 @@
 #elif defined(__ARMEL__)
 #define GOOGLE_PROTOBUF_ARCH_ARM 1
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
-#elif defined(__tile__)
-#define GOOGLE_PROTOBUF_ARCH_TILE 1
-#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
 #elif defined(__aarch64__)
 #define GOOGLE_PROTOBUF_ARCH_AARCH64 1
 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1
@@ -70,12 +65,12 @@
 #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)
+#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
 #define GOOGLE_PROTOBUF_ARCH_POWER 1
 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1
 #elif defined(__GNUC__)
@@ -98,14 +93,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/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..ad84870
--- /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_ : NULL) {
+}
+
+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/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..ec3ffd5
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece.h
@@ -0,0 +1,453 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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/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 7955d26..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
@@ -309,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)
@@ -536,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 {
@@ -652,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
@@ -685,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.
@@ -725,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)) {
@@ -738,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()
@@ -871,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()
@@ -1205,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;
   }
@@ -1236,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
@@ -1247,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
@@ -1260,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;
   }
@@ -1285,24 +1396,6 @@
   return buffer;
 }
 
-string ToHex(uint64 num) {
-  if (num == 0) {
-    return string("0");
-  }
-
-  // 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;
-  }
-
-  return string(bufptr, buf + 16 - bufptr);
-}
-
 namespace strings {
 
 AlphaNum::AlphaNum(strings::Hex hex) {
@@ -1536,5 +1629,661 @@
   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;
+    }
+  }
+
+  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;
+    }
+  }
+
+#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
 }  // namespace google
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
index 920701e..27d4757 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 {
@@ -72,7 +73,33 @@
 }
 
 inline bool ascii_isspace(char c) {
-  return 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;
 }
 
 // ----------------------------------------------------------------------
@@ -287,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);
@@ -360,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);
 }
 
 // ----------------------------------------------------------------------
@@ -451,6 +519,10 @@
   return buffer;
 }
 
+inline string SimpleBtoa(bool value) {
+  return value ? "true" : "false";
+}
+
 // ----------------------------------------------------------------------
 // SimpleItoa()
 //    Description: converts an integer to a string.
@@ -497,28 +569,30 @@
 
 namespace strings {
 
+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 {
-    NONE = 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,
-  } spec;
+  enum PadSpec spec;
   template <class Int>
-  explicit Hex(Int v, PadSpec s = NONE)
+  explicit Hex(Int v, PadSpec s = NO_PAD)
       : spec(s) {
     // Prevent sign-extension by casting integers to
     // their unsigned counterparts.
@@ -534,7 +608,7 @@
   }
 };
 
-struct AlphaNum {
+struct LIBPROTOBUF_EXPORT AlphaNum {
   const char *piece_data_;  // move these to string_ref eventually
   size_t piece_size_;       // move these to string_ref eventually
 
@@ -571,6 +645,9 @@
   AlphaNum(const string& str)
       : piece_data_(str.data()), piece_size_(str.size()) {}
 
+  AlphaNum(StringPiece str)
+      : piece_data_(str.data()), piece_size_(str.size()) {}
+
   size_t size() const { return piece_size_; }
   const char *data() const { return piece_data_; }
 
@@ -610,23 +687,30 @@
 //    be a reference into str.
 // ----------------------------------------------------------------------
 
-string StrCat(const AlphaNum &a, const AlphaNum &b);
-string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c);
-string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
-              const AlphaNum &d);
-string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
-              const AlphaNum &d, const AlphaNum &e);
-string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
-              const AlphaNum &d, const AlphaNum &e, const AlphaNum &f);
-string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
-              const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
-              const AlphaNum &g);
-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 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);
+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);
 
 inline string StrCat(const AlphaNum& a) { return string(a.data(), a.size()); }
 
@@ -651,12 +735,14 @@
 //    worked around as consecutive calls to StrAppend are quite efficient.
 // ----------------------------------------------------------------------
 
-void StrAppend(string* dest, const AlphaNum& a);
-void StrAppend(string* dest, const AlphaNum& a, const AlphaNum& b);
-void StrAppend(string* dest, const AlphaNum& a, const AlphaNum& b,
-               const AlphaNum& c);
-void StrAppend(string* dest, const AlphaNum& a, const AlphaNum& b,
-               const AlphaNum& c, const AlphaNum& d);
+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()
@@ -699,6 +785,83 @@
                                               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);
+
+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/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 b58cae3..0d8127e 100644
--- a/src/google/protobuf/stubs/type_traits.h
+++ b/src/google/protobuf/stubs/type_traits.h
@@ -59,9 +59,9 @@
 #ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_
 #define GOOGLE_PROTOBUF_TYPE_TRAITS_H_
 
+#include <cstddef>                  // for NULL
 #include <utility>                  // For pair
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/template_util.h>  // For true_type and false_type
 
 namespace google {
@@ -73,6 +73,10 @@
   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*);
 
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
index 934f36f..bd646a0 100644
--- a/src/google/protobuf/testdata/golden_message_proto3
+++ 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 5344ec1..3d07b12 100644
--- a/src/google/protobuf/testing/file.cc
+++ b/src/google/protobuf/testing/file.cc
@@ -192,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 ec070c5..b0a5ce6 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -43,13 +43,17 @@
 #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>
@@ -70,6 +74,18 @@
           (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 {
@@ -330,7 +346,17 @@
 
     // 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;
   }
 
@@ -347,15 +373,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
@@ -512,13 +551,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));
@@ -553,13 +586,7 @@
     }
 
     string delimiter;
-    if (TryConsume("<")) {
-      delimiter = ">";
-    } else {
-      DO(Consume("{"));
-      delimiter = "}";
-    }
-
+    DO(ConsumeMessageDelimiter(&delimiter));
     if (field->is_repeated()) {
       DO(ConsumeMessage(reflection->AddMessage(message, field), delimiter));
     } else {
@@ -576,12 +603,7 @@
   // the ending delimiter.
   bool SkipFieldMessage() {
     string delimiter;
-    if (TryConsume("<")) {
-      delimiter = ">";
-    } else {
-      DO(Consume("{"));
-      delimiter = "}";
-    }
+    DO(ConsumeMessageDelimiter(&delimiter));
     while (!LookingAt(">") &&  !LookingAt("}")) {
       DO(SkipField());
     }
@@ -635,7 +657,7 @@
       case FieldDescriptor::CPPTYPE_FLOAT: {
         double value;
         DO(ConsumeDouble(&value));
-        SET_FIELD(Float, static_cast<float>(value));
+        SET_FIELD(Float, io::SafeDoubleToFloat(value));
         break;
       }
 
@@ -808,6 +830,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) {
@@ -947,6 +981,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.
@@ -1273,7 +1358,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);
@@ -1338,7 +1426,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);
 }
 
@@ -1413,11 +1503,63 @@
     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_) {
@@ -1446,6 +1588,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 +1656,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 +1680,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,11 +1780,21 @@
           ? reflection->GetRepeatedStringReference(
               message, field, index, &scratch)
           : reflection->GetStringReference(message, field, &scratch);
+      int64 size = value.size();
+      if (truncate_string_field_longer_than_ > 0) {
+        size = std::min(truncate_string_field_longer_than_,
+                        static_cast<int64>(value.size()));
+      }
+      string truncated_value(value.substr(0, size) + "...<truncated>...");
+      const string* value_to_print = &value;
+      if (size < value.size()) {
+        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;
     }
@@ -1680,8 +1897,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 {
@@ -1692,8 +1909,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 {
@@ -1724,14 +1941,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 9e2cb07..ef3d4a8 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -208,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
@@ -259,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_;
@@ -271,6 +296,10 @@
 
     bool print_message_fields_in_index_order_;
 
+    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;
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 477fdcb..8d61be1 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -32,23 +32,31 @@
 //  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/unittest.pb.h>
-#include <google/protobuf/unittest_mset.pb.h>
-#include <google/protobuf/test_util.h>
-
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.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/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/mathlimits.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
+
 
 namespace google {
 namespace protobuf {
@@ -56,11 +64,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 "
@@ -451,7 +454,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,
@@ -897,8 +900,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 +935,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 +996,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 +1061,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) \
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
new file mode 100644
index 0000000..c1c4402
--- /dev/null
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -0,0 +1,434 @@
+// 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(\005BT\n\023com.google.protobufB\016"
+    "TimestampProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Pr"
+    "otobuf.WellKnownTypesb\006proto3", 189);
+  ::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() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Timestamp*>(16)->f)
+
+#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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Timestamp* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Timestamp>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Timestamp::MergeFrom(const Timestamp& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Timestamp::CopyFrom(const Timestamp& from) {
+  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
index ac8e009..b51fc3f 100644
--- a/src/google/protobuf/timestamp.proto
+++ b/src/google/protobuf/timestamp.proto
@@ -27,15 +27,18 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (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 java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "TimestampProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
 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
@@ -46,15 +49,16 @@
 // 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.)
+// 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()`.
+// 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()`.
+// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
 //
 //     struct timeval tv;
 //     gettimeofday(&tv, NULL);
@@ -63,7 +67,7 @@
 //     timestamp.set_seconds(tv.tv_sec);
 //     timestamp.set_nanos(tv.tv_usec * 1000);
 //
-// Example 3: compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
 //
 //     FILETIME ft;
 //     GetSystemTimeAsFileTime(&ft);
@@ -75,21 +79,24 @@
 //     timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
 //     timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
 //
-// Example 4: compute Timestamp from Java `System.currentTimeMillis()`.
+// 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 Python `datetime.datetime`.
 //
-//     now = datetime.datetime.utcnow()
-//     seconds = int(time.mktime(now.timetuple()))
-//     nanos = now.microsecond * 1000
+// 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.
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
new file mode 100644
index 0000000..7b47b3b
--- /dev/null
+++ b/src/google/protobuf/type.pb.cc
@@ -0,0 +1,3231 @@
+// 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() {
+  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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Type* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Type>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Type::MergeFrom(const Type& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Type::CopyFrom(const Type& from) {
+  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() {
+  
+  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() {
+  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() {
+  
+  ::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() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Field*>(16)->f)
+
+#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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Field* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Field>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Field::MergeFrom(const Field& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Field::CopyFrom(const Field& from) {
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Enum* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Enum>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Enum::MergeFrom(const Enum& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Enum::CopyFrom(const Enum& from) {
+  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() {
+  
+  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() {
+  
+  ::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() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  number_ = 0;
+  options_.Clear();
+}
+
+bool EnumValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EnumValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void EnumValue::MergeFrom(const EnumValue& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void EnumValue::CopyFrom(const EnumValue& from) {
+  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() {
+  
+  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() {
+  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 (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Option* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Option>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Option::MergeFrom(const Option& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Option::CopyFrom(const Option& from) {
+  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() {
+  
+  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() {
+  
+  ::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..76fe8a6
--- /dev/null
+++ b/src/google/protobuf/type.pb.h
@@ -0,0 +1,1696 @@
+// 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() {
+  
+  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() {
+  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() {
+  
+  ::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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  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() {
+  
+  ::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() {
+  
+  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() {
+  
+  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() {
+  
+  ::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 745f77c..85fe615 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -184,6 +184,7 @@
 message NestedTestAllTypes {
   optional NestedTestAllTypes child = 1;
   optional TestAllTypes payload = 2;
+  repeated NestedTestAllTypes repeated_child = 3;
 }
 
 message TestDeprecatedFields {
@@ -202,6 +203,11 @@
   FOREIGN_BAZ = 6;
 }
 
+message TestReservedFields {
+  reserved 2, 15, 9 to 11;
+  reserved "bar", "baz";
+}
+
 message TestAllExtensions {
   extensions 1 to max;
 }
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index d4d6e86..4cc0e36 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -392,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
index 66b31ac..8aa3a37 100644
--- a/src/google/protobuf/unittest_drop_unknown_fields.proto
+++ b/src/google/protobuf/unittest_drop_unknown_fields.proto
@@ -31,6 +31,9 @@
 syntax = "proto3";
 
 package unittest_drop_unknown_fields;
+option objc_class_prefix = "DropUnknowns";
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
 
 message Foo {
   enum NestedEnum {
@@ -38,8 +41,8 @@
     BAR = 1;
     BAZ = 2;
   }
-  optional int32 int32_value = 1;
-  optional NestedEnum enum_value = 2;
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
 }
 
 message FooWithExtraFields {
@@ -49,7 +52,7 @@
     BAZ = 2;
     QUX = 3;
   }
-  optional int32 int32_value = 1;
-  optional NestedEnum enum_value = 2;
-  optional int32 extra_int32_value = 3;
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
+  int32 extra_int32_value = 3;
 }
diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto
index 2250261..6e65dc1 100644
--- a/src/google/protobuf/unittest_enormous_descriptor.proto
+++ b/src/google/protobuf/unittest_enormous_descriptor.proto
@@ -33,7 +33,8 @@
 //  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";
 
diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto
index 7e16522..8d03e38 100644
--- a/src/google/protobuf/unittest_import.proto
+++ b/src/google/protobuf/unittest_import.proto
@@ -64,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_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_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_mset.proto b/src/google/protobuf/unittest_mset.proto
index 3aa31fa..49d9ada 100644
--- a/src/google/protobuf/unittest_mset.proto
+++ b/src/google/protobuf/unittest_mset.proto
@@ -32,33 +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;
@@ -82,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_no_arena.proto b/src/google/protobuf/unittest_no_arena.proto
index 36fb865..41518df 100644
--- a/src/google/protobuf/unittest_no_arena.proto
+++ b/src/google/protobuf/unittest_no_arena.proto
@@ -44,6 +44,7 @@
 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";
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
index e04da0a..994afff 100644
--- a/src/google/protobuf/unittest_no_field_presence.proto
+++ b/src/google/protobuf/unittest_no_field_presence.proto
@@ -41,7 +41,7 @@
 // forms.
 message TestAllTypes {
   message NestedMessage {
-    optional int32 bb = 1;
+    int32 bb = 1;
   }
 
   enum NestedEnum {
@@ -53,36 +53,36 @@
   // Singular
   // TODO: remove 'optional' labels as soon as CL 69188077 is LGTM'd to make
   // 'optional' optional.
-  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;
+     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;
 
-  optional NestedMessage                        optional_nested_message  = 18;
-  optional ForeignMessage                       optional_foreign_message = 19;
-  optional protobuf_unittest.TestAllTypes         optional_proto2_message = 20;
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest.TestAllTypes         optional_proto2_message = 20;
 
-  optional NestedEnum                           optional_nested_enum     = 21;
-  optional ForeignEnum                          optional_foreign_enum    = 22;
+  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;
 
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
 
-  optional NestedMessage optional_lazy_message = 30 [lazy=true];
+  NestedMessage optional_lazy_message = 30 [lazy=true];
 
   // Repeated
   repeated    int32 repeated_int32    = 31;
@@ -122,13 +122,13 @@
 }
 
 message TestProto2Required {
-  optional protobuf_unittest.TestRequired proto2 = 1;
+  protobuf_unittest.TestRequired proto2 = 1;
 }
 
 // Define these after TestAllTypes to make sure the compiler can handle
 // that.
 message ForeignMessage {
-  optional int32 c = 1;
+  int32 c = 1;
 }
 
 enum ForeignEnum {
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto
index 67e5749..2f91332 100644
--- a/src/google/protobuf/unittest_preserve_unknown_enum.proto
+++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto
@@ -31,6 +31,9 @@
 syntax = "proto3";
 
 package proto3_preserve_unknown_enum_unittest;
+option objc_class_prefix = "UnknownEnums";
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
 
 enum MyEnum {
   FOO = 0;
@@ -46,7 +49,7 @@
 }
 
 message MyMessage {
-  optional MyEnum e = 1;
+  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
@@ -57,7 +60,7 @@
 }
 
 message MyMessagePlusExtra {
-  optional MyEnumPlusExtra e = 1;
+  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];
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
index 6d7bada..b835a6b 100644
--- a/src/google/protobuf/unittest_proto3_arena.proto
+++ b/src/google/protobuf/unittest_proto3_arena.proto
@@ -43,7 +43,7 @@
     // 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;
+    int32 bb = 1;
   }
 
   enum NestedEnum {
@@ -55,46 +55,47 @@
   }
 
   // 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;
+     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;
 
-  optional group OptionalGroup = 16 {
-    optional int32 a = 17;
-  }
+  // Groups are not allowed in proto3.
+  // 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;
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message  = 20;
 
-  optional NestedEnum                           optional_nested_enum     = 21;
-  optional ForeignEnum                          optional_foreign_enum    = 22;
+  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;
 
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
 
   // Defined in unittest_import_public.proto
-  optional protobuf_unittest_import.PublicImportMessage
+  protobuf_unittest_import.PublicImportMessage
       optional_public_import_message = 26;
 
-  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+  NestedMessage optional_lazy_message = 27 [lazy=true];
 
   // Repeated
   repeated    int32 repeated_int32    = 31;
@@ -113,9 +114,10 @@
   repeated   string repeated_string   = 44;
   repeated    bytes repeated_bytes    = 45;
 
-  repeated group RepeatedGroup = 46 {
-    optional int32 a = 47;
-  }
+  // 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;
@@ -161,6 +163,24 @@
   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;
@@ -170,7 +190,7 @@
 // Define these after TestAllTypes to make sure the compiler can handle
 // that.
 message ForeignMessage {
-  optional int32 c = 1;
+  int32 c = 1;
 }
 
 enum ForeignEnum {
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_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h
deleted file mode 100644
index 39c10cb..0000000
--- a/src/google/protobuf/unknown_enum_impl.h
+++ /dev/null
@@ -1,155 +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.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
-#define GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
-
-#include <stdlib.h>
-
-#include <google/protobuf/stubs/common.h>
-#include "net/proto/tagmapper.h"
-#include <google/protobuf/bridge/compatibility_mode_support.h>
-
-namespace google {
-namespace protobuf {
-
-// google/protobuf/message.h
-class Message;
-
-namespace util {
-
-// NOTE: You should not call these functions directly.  Instead use either
-// HAS_UNKNOWN_ENUM() or GET_UNKNOWN_ENUM(), defined in the public header.
-// The macro-versions operate in a type-safe manner and behave appropriately
-// for the proto version of the message, whereas these versions assume a
-// specific proto version and allow the caller to pass in any arbitrary integer
-// value as a field number.
-//
-// Returns whether the message has unrecognized the enum value for a given
-// field. It also stores the value into the unknown_value parameter if the
-// function returns true and the pointer is not NULL.
-//
-// In proto2, invalid enum values will be treated as unknown fields. This
-// function checks that case.
-bool HasUnknownEnum(const Message& message, int32 field_number,
-                    int32* unknown_value = nullptr);
-// Same as above, but returns all unknown enums.
-bool GetRepeatedEnumUnknowns(const Message& message, int32 field_number,
-                             vector<int32>* unknown_values = nullptr);
-// In proto1, invalue enum values are stored in the same way as valid enum
-// values.
-// TODO(karner): Delete this once the migration to proto2 is complete.
-bool HasUnknownEnumProto1(const Message& message, int32 field_number,
-                          int32* unknown_value);
-// Same as above, but returns all unknown enums.
-bool GetRepeatedEnumUnknownsProto1(const Message& message, int32 field_number,
-                                   vector<int32>* unknown_values);
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-bool HasUnknownEnum_Template(const T& message, int32 field_number,
-                             int32* unknown_value = nullptr) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    return HasUnknownEnum(message, field_number, unknown_value);
-  } else {
-    return HasUnknownEnumProto1(message, field_number, unknown_value);
-  }
-}
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-bool GetRepeatedEnumUnknowns_Template(
-    const T& message, int32 field_number,
-    vector<int32>* unknown_values = nullptr) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    return GetRepeatedEnumUnknowns(message, field_number, unknown_values);
-  } else {
-    return GetRepeatedEnumUnknownsProto1(message, field_number,
-                                         unknown_values);
-  }
-}
-
-// NOTE: You should not call these functions directly.  Instead use
-// CLEAR_UNKNOWN_ENUM(), defined in the public header.  The macro-versions
-// operate in a type-safe manner and behave appropriately for the proto
-// version of the message, whereas these versions assume a specific proto
-// version and allow the caller to pass in any arbitrary integer value as a
-// field number.
-//
-// Clears the unknown entries of the given field of the message.
-void ClearUnknownEnum(Message* message, int32 field_number);
-// In proto1, clears the field if the value is out of range.
-// TODO(karner): Delete this or make it proto2-only once the migration
-// to proto2 is complete.
-void ClearUnknownEnumProto1(Message* message, int32 field_number);
-template <typename T>
-void ClearUnknownEnum_Template(T* message, int32 field_number) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    ClearUnknownEnum(message, field_number);
-  } else {
-    ClearUnknownEnumProto1(message, field_number);
-  }
-}
-
-// NOTE: You should not call these functions directly.  Instead use
-// SET_UNKNOWN_ENUM(), defined in the public header.  The macro-versions
-// operate in a type-safe manner and behave appropriately for the proto
-// version of the message, whereas these versions assume a specific proto
-// version and allow the caller to pass in any arbitrary integer value as a
-// field number.
-//
-// Sets the given value in the unknown fields of the message.
-void SetUnknownEnum(Message* message, int32 field_number, int32 unknown_value);
-// In proto1, invalue enum values are stored in the same way as valid enum
-// values.
-// TODO(karner): Delete this once the migration to proto2 is complete.
-void SetUnknownEnumProto1(Message* message, int32 field_number,
-                          int32 unknown_value);
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-void SetUnknownEnum_Template(T* message, int32 field_number,
-                             int32 unknown_value) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    SetUnknownEnum(message, field_number, unknown_value);
-  } else {
-    SetUnknownEnumProto1(message, field_number, unknown_value);
-  }
-}
-
-}  // namespace util
-}  // namespace protobuf
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
diff --git a/src/google/protobuf/unknown_enum_test.proto b/src/google/protobuf/unknown_enum_test.proto
deleted file mode 100644
index caafadc..0000000
--- a/src/google/protobuf/unknown_enum_test.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.
-
-// Definitions of protos for testing cross-version compatibility.  The
-// UpRevision message acts as if it were a newer version of the DownRevision
-// message.  That is, UpRevision shares all the same fields as DownRevision,
-// but UpRevision can add fields and add enum values.
-syntax = "proto2";
-
-package google.protobuf.util;
-
-
-message DownRevision {
-  enum Enum {
-    DEFAULT_VALUE = 2;
-    NONDEFAULT_VALUE = 3;
-  }
-
-  optional Enum value = 1 [default = DEFAULT_VALUE];
-  repeated Enum values = 2;
-}
-
-message UpRevision {
-  enum Enum {
-    DEFAULT_VALUE = 2;
-    NONDEFAULT_VALUE = 3;
-    NEW_VALUE = 4;
-    NEW_VALUE_2 = 5;
-    NEW_VALUE_3 = 6;
-  }
-
-  optional Enum value = 1 [default = DEFAULT_VALUE];
-  repeated Enum values = 2;
-}
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index e15280c..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>
@@ -50,8 +51,13 @@
 // 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_);
@@ -93,7 +99,7 @@
     fields_ = new vector<UnknownField>();
     for (int i = 0; i < other_field_count; i++) {
       fields_->push_back((*other.fields_)[i]);
-      fields_->back().DeepCopy();
+      fields_->back().DeepCopy((*other.fields_)[i]);
     }
   }
 }
@@ -104,7 +110,7 @@
     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();
+      fields_->back().DeepCopy((*other.fields_)[i]);
     }
   }
 }
@@ -202,7 +208,7 @@
 void UnknownFieldSet::AddField(const UnknownField& field) {
   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) {
@@ -303,7 +309,7 @@
   }
 }
 
-void UnknownField::DeepCopy() {
+void UnknownField::DeepCopy(const UnknownField& other) {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
       length_delimited_.string_value_ = new string(
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 987b197..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 {
@@ -216,7 +217,7 @@
   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.
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index 9b02f0b..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>
diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc
new file mode 100644
index 0000000..9f61326
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator.cc
@@ -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.
+
+// 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:
+      COMPARE_FIELD(String);
+    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..8b83c69
--- /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 four modes of floating
+// point value comparison: exact, approximate using MathUtil::AlmostEqual
+// method, and arbitrarilly 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..23f7d51
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -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.
+
+// 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..c59f43a
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -0,0 +1,418 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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::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..92f6989
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -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.
+
+#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 according to proto3 JSON
+  // spec for FieldMask (e.g., "foo,bar,baz.quz").
+  static string ToString(const FieldMask& mask);
+  static void FromString(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:
+  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..a952325
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util_test.cc
@@ -0,0 +1,395 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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 {
+namespace {
+
+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");
+  EXPECT_EQ("foo", FieldMaskUtil::ToString(mask));
+  mask.add_paths("bar");
+  EXPECT_EQ("foo,bar", FieldMaskUtil::ToString(mask));
+
+  FieldMaskUtil::FromString("", &mask);
+  EXPECT_EQ(0, mask.paths_size());
+  FieldMaskUtil::FromString("foo", &mask);
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_EQ("foo", mask.paths(0));
+  FieldMaskUtil::FromString("foo,bar", &mask);
+  EXPECT_EQ(2, mask.paths_size());
+  EXPECT_EQ("foo", mask.paths(0));
+  EXPECT_EQ("bar", 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..0cb8f6e
--- /dev/null
+++ b/src/google/protobuf/util/internal/constants.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.
+
+#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[] = "%Y-%m-%dT%H:%M:%S";
+
+// Minimum seconds allowed in a google.protobuf.TimeStamp or Duration value.
+const int64 kMinSeconds = -315576000000;
+
+// Maximum seconds allowed in a google.protobuf.TimeStamp or Duration value.
+const int64 kMaxSeconds = 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..b557429
--- /dev/null
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -0,0 +1,324 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 (!WebSafeBase64Unescape(str_, &decoded)) {
+      if (!Base64Unescape(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 {
+  To result;
+  if (func(str_, &result)) return result;
+  return InvalidArgument(StrCat("\"", str_.ToString(), "\""));
+}
+
+}  // 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..f22bfe7
--- /dev/null
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -0,0 +1,213 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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) {}
+  explicit DataPiece(StringPiece value)
+      : type_(TYPE_STRING),
+        str_(StringPiecePod::CreateFromStringPiece(value)) {}
+  // Constructor for bytes. The second parameter is not used.
+  explicit DataPiece(StringPiece value, bool dummy)
+      : type_(TYPE_BYTES), str_(StringPiecePod::CreateFromStringPiece(value)) {}
+  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;
+
+  // Data type for this piece of data.
+  Type type_;
+
+  // 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 {
+    const char* data;
+    int size;
+
+    // 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);
+    }
+
+    string ToString() const { return string(data, size); }
+  };
+
+  // Stored piece of data.
+  union {
+    int32 i32_;
+    int64 i64_;
+    uint32 u32_;
+    uint64 u64_;
+    double double_;
+    float float_;
+    bool bool_;
+    StringPiecePod str_;
+  };
+};
+
+}  // 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..a63e560
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -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.
+
+#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).*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),
+      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()));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
+    StringPiece name, StringPiece value) {
+  if (current_ == NULL) {
+    ow_->RenderBytes(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
+    StringPiece name) {
+  if (current_ == NULL) {
+    ow_->RenderNull(name);
+  } else {
+    RenderDataPiece(name, DataPiece::NullData());
+  }
+  return this;
+}
+
+DefaultValueObjectWriter::Node::Node(const string& name,
+                                     const google::protobuf::Type* type,
+                                     NodeKind kind, const DataPiece& data,
+                                     bool is_placeholder)
+    : name_(name),
+      type_(type),
+      kind_(kind),
+      is_any_(false),
+      data_(data),
+      is_placeholder_(is_placeholder) {}
+
+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);
+    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));
+    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());
+
+  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())
+             : 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());
+    }
+    case google::protobuf::Field_Kind_TYPE_BYTES: {
+      return DataPiece(field.default_value(), false);
+    }
+    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) {
+    root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(),
+                         false));
+    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 = 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) {
+    root_.reset(
+        new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false));
+    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 = 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 = 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..695b9dd
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -0,0 +1,234 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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:
+  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);
+
+ 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);
+    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 google::protobuf::Type* type() { return type_; }
+
+    void set_type(const google::protobuf::Type* type) { type_ = type; }
+
+    NodeKind kind() { return kind_; }
+
+    int number_of_children() { return children_.size(); }
+
+    void set_data(const DataPiece& data) { data_ = data; }
+
+    bool is_any() { 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_;
+  };
+
+  // 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_;
+
+  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..94d2ab7
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter.cc
@@ -0,0 +1,181 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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;
+  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..761a0a1
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter.h
@@ -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.
+
+#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()) {
+  }
+  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);
+
+ 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_;
+
+  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..9d82016
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter_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/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_;
+  ObjectWriter* 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()));
+}
+
+}  // 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..df91675
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -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.
+
+#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/stubs/strutil.h>
+#include <google/protobuf/util/internal/object_writer.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 a unicode escape sequence (/uXXXX)
+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]);
+  }
+  char buf[UTFmax];
+  int len = EncodeAsUTF8Char(code, buf);
+  // Advance past the unicode 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 == '-') 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) {
+    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;
+  }
+
+  // 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 = max(p_start - kContextLength, json_start);
+  const char* end = 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(
+      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..3414826
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc
@@ -0,0 +1,716 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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) {
+    util::Status result = RunTest(json, split);
+    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);
+  }
+}
+
+// - 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.");
+}
+
+#ifndef _MSC_VER
+// - unicode handling in strings
+TEST_F(JsonStreamParserTest, UnicodeEscaping) {
+  StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    // TODO(xiaofeng): Figure out what default encoding to use for JSON strings.
+    // In protobuf we use UTF-8 for strings, but for JSON we probably should
+    // allow different encodings?
+    ow_.StartList("")->RenderString("", "\u0639\u0631\u0628\u0649")->EndList();
+    DoTest(str, i);
+  }
+}
+#endif
+
+// - 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 unicode sequence.
+TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) {
+  StringPiece str = "\"\\u12";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Illegal hex string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) {
+  StringPiece str = "\"\\u12$4hello";
+  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..e695f45
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -0,0 +1,121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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);
+
+ protected:
+  ObjectWriter() {}
+
+ private:
+  // 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..47e0009
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -0,0 +1,744 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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;
+  }
+
+    WriteTag(*field);
+  element_.reset(new ProtoElement(element_.release(), field, *type, false));
+  return this;
+}
+
+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;
+  }
+
+  element_.reset(new ProtoElement(element_.release(), field, *type, true));
+  return this;
+}
+
+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;
+  }
+
+  // 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;
+}
+
+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;
+}
+
+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..e631e56
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -0,0 +1,315 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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));
+  }
+  virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) {
+    return RenderDataPiece(name, DataPiece(value, false));
+  }
+  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() const { 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);
+
+ 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..034d616
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -0,0 +1,1045 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 {
+// 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);
+}  // 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) {
+  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) {
+  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()) {
+          return Status(util::error::INTERNAL, "Map key must be non-empty");
+        }
+        RETURN_IF_ERROR(RenderField(field, map_key, ow));
+      }
+    }
+    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 > kMaxSeconds || seconds < kMinSeconds) {
+    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 > kMaxSeconds || seconds < kMinSeconds) {
+    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(WriteMessage(*type, field_name, 0, true, ow));
+    }
+    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) {
+          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);
+}
+
+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..78defa1
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -0,0 +1,248 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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;
+
+ 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;
+
+  // 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_;
+
+
+  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..561f676
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -0,0 +1,830 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <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::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::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_) {
+    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)));
+    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;
+  }
+
+  testing::TypeInfoTestHelper helper_;
+
+  ::testing::NiceMock<MockObjectWriter> mock_;
+  ExpectingObjectWriter ow_;
+};
+
+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());
+}
+
+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());
+}
+
+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());
+}
+
+}  // 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..786bf0b
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -0,0 +1,1133 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)
+    : ProtoWriter(type_resolver, type, output, listener),
+      master_type_(type),
+      current_(NULL) {}
+
+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) {}
+
+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),
+      has_injected_value_message_(false) {}
+
+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 (!has_injected_value_message_ || depth_ != 1 || name != "value") {
+    // We don't propagate to ow_ StartObject("value") calls for nested Anys or
+    // Struct at depth 1 as they are nested one level deep with an injected
+    // "value" field.
+    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_.  If we are in a
+  // nested Any or Struct type, ignore the second to last EndObject call (depth_
+  // == -1)
+  if (ow_ != NULL && (!has_injected_value_message_ || depth_ >= 0)) {
+    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 {
+    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 {
+    // Check to see if the data needs to be rendered with well-known-type
+    // renderer.
+    const TypeRenderer* type_renderer =
+        FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name()));
+    if (type_renderer) {
+      Status status = (*type_renderer)(ow_.get(), value);
+      if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
+    } 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();
+
+  // If this is the case of an Any in an Any or Struct in an Any, we need to
+  // expect a StartObject call with "value" while we're at depth_ 0, which we
+  // should ignore (not propagate to our nested object writer). We also need to
+  // ignore the second-to-last EndObject call, and not propagate that either.
+  if (type->name() == kAnyType || type->name() == kStructType) {
+    has_injected_value_message_ = true;
+  }
+
+  // Create our object writer and initialize it with the first StartObject
+  // call.
+  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
+                                        parent_->listener()));
+  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));
+    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));
+    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:
+    case DataPiece::TYPE_UINT64:
+    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)));
+  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 > kMaxSeconds || seconds < kMinSeconds ||
+      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));
+    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) {
+      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..08ac6e3
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -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.
+
+#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:
+// Constructor. Does not take ownership of any parameter passed in.
+  ProtoStreamObjectWriter(TypeResolver* type_resolver,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener);
+  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 message type contained in Any has a special "value" message
+    // injected. This is true for well-known message types like Any or Struct.
+    bool has_injected_value_message_;
+  };
+
+  // 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_;
+
+  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..5f9ffb9
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -0,0 +1,1895 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+
+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_));
+  }
+
+  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_;
+};
+
+MATCHER_P(HasObjectLocation, expected,
+          "Verifies the expected object location") {
+  string actual;
+#if __cplusplus >= 201103L
+  actual = std::get<0>(arg).ToString();
+#else
+  actual = std::tr1::get<0>(arg).ToString();
+#endif
+  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);
+
+  ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()),
+                                   output_.get(), &listener_));
+
+  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");
+
+  ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()),
+                                   output_.get(), &listener_));
+
+  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");
+
+  ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()),
+                                   output_.get(), &listener_));
+
+  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, 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: "
+                               "-8032-10-18T00:00:00.000Z")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "-8032-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, 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() {
+    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();
+}
+
+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());
+    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);
+}
+
+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..82b8176
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -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.
+
+// 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;
+
+  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.
+}
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..1b9c515
--- /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 google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url);
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output,
+                                         listener);
+    }
+  }
+  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..6916a73
--- /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/type_info.h>
+#include <google/protobuf/util/internal/default_value_objectwriter.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);
+
+  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..1ddf248
--- /dev/null
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -0,0 +1,356 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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() && isspace(str[i]); ++i) {
+  }
+  GOOGLE_DCHECK(i == str.size() || !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;
+      } 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;
+      }
+    }
+    result.push_back(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..c3b8d50
--- /dev/null
+++ b/src/google/protobuf/util/json_util.cc
@@ -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.
+
+#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);
+}
+
+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);
+  converter::NoopErrorListener 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 util::Status::OK;
+}
+
+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..da68495
--- /dev/null
+++ b/src/google/protobuf/util/json_util_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/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;
+    GOOGLE_CHECK_OK(JsonToBinaryString(
+        resolver_.get(), GetTypeUrl(message->GetDescriptor()), json, &binary));
+    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));
+}
+
+// TODO(skarvaje): Uncomment after cl/96232915 is submitted.
+// 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\":\"\","
+      // // TODO(xiaofeng): The default enum value should be FOO. I believe
+      // // this is a bug in DefaultValueObjectWriter.
+      // "\"enumValue\":null"
+      // "}",
+      // 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());
+}
+
+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..0f879dc
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -0,0 +1,1686 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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.";
+    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_LOG(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_LOG(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 c5bbbf2..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(
@@ -469,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
@@ -641,10 +637,19 @@
 
       // 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 {
@@ -829,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);
@@ -902,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;
       }
@@ -996,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
@@ -1116,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 8de491a..941be75 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -231,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.
@@ -247,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,
@@ -265,8 +258,6 @@
                                            Message* message,
                                            io::CodedInputStream* input);
 
-
-
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat);
 };
 
@@ -290,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());
@@ -321,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;
@@ -332,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);
 #endif
 }
 
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index 2ce4920..7f1093c 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;
@@ -484,9 +489,9 @@
   }
 }
 
-static inline bool ReadBytesToString(io::CodedInputStream* input,
-                                     string* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-static inline bool ReadBytesToString(io::CodedInputStream* input,
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE static bool ReadBytesToString(
+    io::CodedInputStream* input, string* value);
+inline static bool ReadBytesToString(io::CodedInputStream* input,
                                      string* value) {
   uint32 length;
   return input->ReadVarint32(&length) &&
@@ -504,6 +509,35 @@
   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
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 76bc75a..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,16 +275,14 @@
   //
   // 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.
@@ -318,6 +316,16 @@
   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);
 
@@ -330,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);
@@ -399,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
@@ -516,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[];
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 129fc63..79493ca 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -43,6 +43,7 @@
 
 #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>
@@ -411,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
 
@@ -470,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;
@@ -478,6 +479,14 @@
   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;
@@ -491,6 +500,17 @@
   // 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.
+  return input->CheckEntireMessageConsumedAndPopLimit(old_limit);
+}
 
 // ===================================================================
 
@@ -815,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 a3062a6..15c3755 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -38,9 +38,12 @@
 #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/testing/googletest.h>
 #include <gtest/gtest.h>
@@ -418,7 +421,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 +464,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 +541,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 +555,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 +585,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 +593,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 +605,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 +770,7 @@
 }
 
 TEST(WireFormatTest, CompatibleTypes) {
-  const int64 data = 0x100000000;
+  const int64 data = 0x100000000LL;
   unittest::Int64Message msg1;
   msg1.set_data(data);
   string serialized;
@@ -794,6 +797,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
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
new file mode 100644
index 0000000..212dd21
--- /dev/null
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -0,0 +1,2695 @@
+// 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(\014BS\n\023com"
+    ".google.protobufB\rWrappersProtoP\001\240\001\001\370\001\001\242"
+    "\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006"
+    "proto3", 406);
+  ::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() {
+  value_ = 0;
+}
+
+bool DoubleValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DoubleValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DoubleValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void DoubleValue::MergeFrom(const DoubleValue& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void DoubleValue::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DoubleValue::CopyFrom(const DoubleValue& from) {
+  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() {
+  value_ = 0;
+}
+
+bool FloatValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FloatValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FloatValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void FloatValue::MergeFrom(const FloatValue& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void FloatValue::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FloatValue::CopyFrom(const FloatValue& from) {
+  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() {
+  value_ = GOOGLE_LONGLONG(0);
+}
+
+bool Int64Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Int64Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Int64Value>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Int64Value::MergeFrom(const Int64Value& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void Int64Value::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Int64Value::CopyFrom(const Int64Value& from) {
+  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() {
+  value_ = GOOGLE_ULONGLONG(0);
+}
+
+bool UInt64Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const UInt64Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UInt64Value>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void UInt64Value::MergeFrom(const UInt64Value& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void UInt64Value::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void UInt64Value::CopyFrom(const UInt64Value& from) {
+  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() {
+  value_ = 0;
+}
+
+bool Int32Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Int32Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Int32Value>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void Int32Value::MergeFrom(const Int32Value& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void Int32Value::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Int32Value::CopyFrom(const Int32Value& from) {
+  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() {
+  value_ = 0u;
+}
+
+bool UInt32Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const UInt32Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UInt32Value>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void UInt32Value::MergeFrom(const UInt32Value& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void UInt32Value::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void UInt32Value::CopyFrom(const UInt32Value& from) {
+  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() {
+  value_ = false;
+}
+
+bool BoolValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BoolValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const BoolValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void BoolValue::MergeFrom(const BoolValue& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void BoolValue::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BoolValue::CopyFrom(const BoolValue& from) {
+  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() {
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool StringValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const StringValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const StringValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void StringValue::MergeFrom(const StringValue& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void StringValue::CopyFrom(const StringValue& from) {
+  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() {
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* StringValue::unsafe_arena_release_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_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() {
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool BytesValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(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 {
+  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) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BytesValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const BytesValue>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void BytesValue::MergeFrom(const BytesValue& from) {
+  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) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BytesValue::CopyFrom(const BytesValue& from) {
+  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() {
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* BytesValue::unsafe_arena_release_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_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..7dca938
--- /dev/null
+++ b/src/google/protobuf/wrappers.pb.h
@@ -0,0 +1,1176 @@
+// 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() {
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* StringValue::unsafe_arena_release_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_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() {
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* BytesValue::unsafe_arena_release_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_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
index 5164c24..040d8a2 100644
--- a/src/google/protobuf/wrappers.proto
+++ b/src/google/protobuf/wrappers.proto
@@ -37,60 +37,81 @@
 
 package google.protobuf;
 
-option java_multiple_files = true;
-option java_outer_classname = "WrappersProto";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
 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.
+// Wrapper message for `double`.
+//
+// The JSON representation for `DoubleValue` is JSON number.
 message DoubleValue {
   // The double value.
   double value = 1;
 }
 
-// Wrapper message for float.
+// Wrapper message for `float`.
+//
+// The JSON representation for `FloatValue` is JSON number.
 message FloatValue {
   // The float value.
   float value = 1;
 }
 
-// Wrapper message for int64.
+// Wrapper message for `int64`.
+//
+// The JSON representation for `Int64Value` is JSON string.
 message Int64Value {
   // The int64 value.
   int64 value = 1;
 }
 
-// Wrapper message for uint64.
+// Wrapper message for `uint64`.
+//
+// The JSON representation for `UInt64Value` is JSON string.
 message UInt64Value {
   // The uint64 value.
   uint64 value = 1;
 }
 
-// Wrapper message for int32.
+// Wrapper message for `int32`.
+//
+// The JSON representation for `Int32Value` is JSON number.
 message Int32Value {
   // The int32 value.
   int32 value = 1;
 }
 
-// Wrapper message for uint32.
+// Wrapper message for `uint32`.
+//
+// The JSON representation for `UInt32Value` is JSON number.
 message UInt32Value {
   // The uint32 value.
   uint32 value = 1;
 }
 
-// Wrapper message for bool.
+// 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.
+// Wrapper message for `string`.
+//
+// The JSON representation for `StringValue` is JSON string.
 message StringValue {
   // The string value.
   string value = 1;
 }
 
-// Wrapper message for bytes.
+// Wrapper message for `bytes`.
+//
+// The JSON representation for `BytesValue` is JSON string.
 message BytesValue {
   // The bytes value.
   bytes value = 1;
diff --git a/travis.sh b/travis.sh
new file mode 100755
index 0000000..c973ec6
--- /dev/null
+++ b/travis.sh
@@ -0,0 +1,311 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# For when some other test needs the C++ main build, including protoc and
+# libprotobuf.
+internal_build_cpp() {
+  if [ $(uname -s) == "Linux" ]; 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 ..
+}
+
+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
+
+  # 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
+
+  (cd csharp/src; mono ../../nuget.exe 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)
+      sudo apt-get install openjdk-6-jdk
+      export PATH=/usr/lib/jvm/java-6-openjdk-amd64/bin:$PATH
+      ;;
+    jdk7)
+      sudo apt-get install openjdk-7-jdk
+      export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH
+      ;;
+    oracle7)
+      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
+      export PATH=/usr/lib/jvm/java-7-oracle/bin:$PATH
+      ;;
+  esac
+
+  which java
+  java -version
+}
+
+build_java() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd java && mvn test && mvn install
+  cd util && mvn test
+  cd ../..
+}
+
+build_java_with_conformance_tests() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd java && mvn test && mvn install
+  cd util && mvn test && mvn 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
+}
+build_java_jdk7() {
+  use_java jdk7
+  build_java_with_conformance_tests
+}
+build_java_oracle7() {
+  use_java oracle7
+  build_java
+}
+
+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() {
+  # 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
+    # Throw -newSimulatorInstance in incase it helps with the flake that
+    # started happening after xctool 0.2.8 got released.
+    internal_xctool_debug_and_release \
+      -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+      -scheme ProtocolBuffers \
+      -sdk iphonesimulator \
+      -destination "${i}" \
+      run-tests \
+      -newSimulatorInstance
+  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 ..
+}
+
+# -------- 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 |
+            ruby_19 |
+            ruby_20 |
+            ruby_21 |
+            ruby_22 |
+            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/python/BUILD b/util/python/BUILD
new file mode 100644
index 0000000..358c381
--- /dev/null
+++ b/util/python/BUILD
@@ -0,0 +1,8 @@
+# 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
+# //util/python:python_headers dependency that in turn provides Python.h.
+cc_library(
+    name = "python_headers",
+    visibility = ["//visibility:public"],
+)
diff --git a/vsprojects/config.h b/vsprojects/config.h
deleted file mode 100755
index a93bb03..0000000
--- a/vsprojects/config.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* protobuf config.h for MSVC.  On other platforms, this is generated
- * automatically by autoheader / autoconf / configure. */
-
-#include <google/protobuf/stubs/pbconfig.h>
-
-#define HASH_MAP_H GOOGLE_PROTOBUF_HASH_MAP_H
-#define HASH_NAMESPACE GOOGLE_PROTOBUF_HASH_NAMESPACE
-#define HASH_SET_H GOOGLE_PROTOBUF_HASH_SET_H
-
-#ifdef GOOGLE_PROTOBUF_HAVE_HASH_MAP
-#define HAVE_HASH_MAP GOOGLE_PROTOBUF_HAVE_HASH_MAP
-#endif
-
-#ifdef GOOGLE_PROTOBUF_HAVE_HASH_SET
-#define HAVE_HASH_SET GOOGLE_PROTOBUF_HAVE_HASH_SET
-#endif
-
-/* 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 ddf7f33..0000000
--- a/vsprojects/extract_includes.bat
+++ /dev/null
@@ -1,87 +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\javanano
-md include\google\protobuf\compiler\python
-md include\google\protobuf\compiler\ruby
-copy ..\src\google\protobuf\arena.h include\google\protobuf\arena.h
-copy ..\src\google\protobuf\arenastring.h include\google\protobuf\arenastring.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\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h
-copy ..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h
-copy ..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
-copy ..\src\google\protobuf\compiler\javanano\javanano_generator.h include\google\protobuf\compiler\javanano\javanano_generator.h
-copy ..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
-copy ..\src\google\protobuf\compiler\plugin.h include\google\protobuf\compiler\plugin.h
-copy ..\src\google\protobuf\compiler\plugin.pb.h include\google\protobuf\compiler\plugin.pb.h
-copy ..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h
-copy ..\src\google\protobuf\compiler\ruby\ruby_generator.h include\google\protobuf\compiler\ruby\ruby_generator.h
-copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.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\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_enum_util.h include\google\protobuf\generated_enum_util.h
-copy ..\src\google\protobuf\generated_message_reflection.h include\google\protobuf\generated_message_reflection.h
-copy ..\src\google\protobuf\generated_message_util.h include\google\protobuf\generated_message_util.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\map_entry.h include\google\protobuf\map_entry.h
-copy ..\src\google\protobuf\map_entry_lite.h include\google\protobuf\map_entry_lite.h
-copy ..\src\google\protobuf\map_field.h include\google\protobuf\map_field.h
-copy ..\src\google\protobuf\map_field_lite.h include\google\protobuf\map_field_lite.h
-copy ..\src\google\protobuf\map_field_inl.h include\google\protobuf\map_field_inl.h
-copy ..\src\google\protobuf\map.h include\google\protobuf\map.h
-copy ..\src\google\protobuf\map_type_handler.h include\google\protobuf\map_type_handler.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\metadata.h include\google\protobuf\metadata.h
-copy ..\src\google\protobuf\reflection.h include\google\protobuf\reflection.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\repeated_field_reflection.h include\google\protobuf\repeated_field_reflection.h
-copy ..\src\google\protobuf\service.h include\google\protobuf\service.h
-copy ..\src\google\protobuf\stubs\atomicops.h include\google\protobuf\stubs\atomicops.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_aix.h include\google\protobuf\stubs\atomicops_internals_aix.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_arm64_gcc.h include\google\protobuf\stubs\atomicops_internals_arm64_gcc.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_arm_gcc.h include\google\protobuf\stubs\atomicops_internals_arm_gcc.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_arm_qnx.h include\google\protobuf\stubs\atomicops_internals_arm_qnx.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_atomicword_compat.h include\google\protobuf\stubs\atomicops_internals_atomicword_compat.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_generic_gcc.h include\google\protobuf\stubs\atomicops_internals_generic_gcc.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_macosx.h include\google\protobuf\stubs\atomicops_internals_macosx.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_mips_gcc.h include\google\protobuf\stubs\atomicops_internals_mips_gcc.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_pnacl.h include\google\protobuf\stubs\atomicops_internals_pnacl.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_solaris.h include\google\protobuf\stubs\atomicops_internals_solaris.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_tsan.h include\google\protobuf\stubs\atomicops_internals_tsan.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.h include\google\protobuf\stubs\atomicops_internals_x86_gcc.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\atomic_sequence_num.h include\google\protobuf\stubs\atomic_sequence_num.h
-copy ..\src\google\protobuf\stubs\casts.h include\google\protobuf\stubs\casts.h
-copy ..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h
-copy ..\src\google\protobuf\stubs\fastmem.h include\google\protobuf\stubs\fastmem.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\singleton.h include\google\protobuf\stubs\singleton.h
-copy ..\src\google\protobuf\stubs\hash.h include\google\protobuf\stubs\hash.h
-copy ..\src\google\protobuf\stubs\stl_util.h include\google\protobuf\stubs\stl_util.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\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 google\protobuf\stubs\pbconfig.h include\google\protobuf\stubs\pbconfig.h
diff --git a/vsprojects/google/protobuf/stubs/pbconfig.h b/vsprojects/google/protobuf/stubs/pbconfig.h
deleted file mode 100755
index 18250a2..0000000
--- a/vsprojects/google/protobuf/stubs/pbconfig.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* protobuf config.h for MSVC.  On other platforms, this is generated
- * automatically by autoheader / autoconf / configure. */
-
-// NOTE: if you add new macros in this file manually, please propagate the macro
-// to vsprojects/config.h.
-
-/* 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
-// 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.
-#if _MSC_VER >= 1600
-#define GOOGLE_PROTOBUF_HASH_NAMESPACE std
-#define GOOGLE_PROTOBUF_HASH_MAP_H <unordered_map>
-#define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
-#define GOOGLE_PROTOBUF_HASH_SET_H <unordered_set>
-#define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
-#elif _MSC_VER >= 1310
-#define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
-#define GOOGLE_PROTOBUF_HASH_MAP_H <hash_map>
-#define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
-#define GOOGLE_PROTOBUF_HASH_SET_H <hash_set>
-#define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
-#else
-#define GOOGLE_PROTOBUF_HASH_NAMESPACE std
-#define GOOGLE_PROTOBUF_HASH_MAP_H <hash_map>
-#define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
-#define GOOGLE_PROTOBUF_HASH_SET_H <hash_set>
-#define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
-#endif
-
-/* the location of <hash_set> */
-
-/* define if the compiler has hash_map */
-#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
-
-/* define if the compiler has hash_set */
-#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
diff --git a/vsprojects/libprotobuf-lite.vcproj b/vsprojects/libprotobuf-lite.vcproj
deleted file mode 100644
index d245448..0000000
--- a/vsprojects/libprotobuf-lite.vcproj
+++ /dev/null
@@ -1,321 +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="$(OutDir)\$(ProjectName)"
-			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="$(OutDir)\$(ProjectName)"
-			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=".\google\protobuf\stubs\pbconfig.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\generated_enum_util.h"></File>
-			<File RelativePath="..\src\google\protobuf\map_entry_lite.h"></File>
-			<File RelativePath="..\src\google\protobuf\map_field_lite.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\stubs\atomicops_internals_x86_gcc.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\arena.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\arenastring.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\repeated_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream.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>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/libprotobuf.vcproj b/vsprojects/libprotobuf.vcproj
deleted file mode 100644
index e782885..0000000
--- a/vsprojects/libprotobuf.vcproj
+++ /dev/null
@@ -1,505 +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="$(OutDir)\$(ProjectName)"
-			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="$(OutDir)\$(ProjectName)"
-			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=".\google\protobuf\stubs\pbconfig.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\generated_enum_util.h"></File>
-			<File RelativePath="..\src\google\protobuf\map_entry_lite.h"></File>
-			<File RelativePath="..\src\google\protobuf\map_field_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\stubs\atomicops_internals_x86_gcc.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\arena.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\arenastring.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\map_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message_lite.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\coded_stream.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\strutil.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\strutil.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\substitute.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\substitute.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\structurally_valid.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor_database.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\dynamic_message.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\message.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\reflection_internal.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\reflection_ops.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\service.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\text_format.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\io\gzip_stream.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\printer.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\strtod.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\tokenizer.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\importer.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\parser.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj
deleted file mode 100644
index 455c2cc..0000000
--- a/vsprojects/libprotoc.vcproj
+++ /dev/null
@@ -1,542 +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="$(OutDir)\$(ProjectName)"
-      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="$(OutDir)\$(ProjectName)"
-      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\javanano\javanano_enum_field.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_extension.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_field.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_file.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_generator.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_helpers.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_map_field.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message_field.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_params.h"></File>
-      <File RelativePath="..\src\google\protobuf\compiler\javanano\javanano_primitive_field.h"></File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\python\python_generator.h"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\ruby\ruby_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\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_map_field.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\ruby\ruby_generator.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\java\java_context.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.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_map_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\javanano\javanano_enum.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum_field.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_extension.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_field.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_file.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_generator.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_helpers.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_map_field.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_message_field.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\javanano\javanano_primitive_field.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\python\python_generator.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\subprocess.cc"
-        >
-      </File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\zip_writer.cc"
-        >
-      </File>
-    </Filter>
-  </Files>
-  <Globals>
-  </Globals>
-</VisualStudioProject>
diff --git a/vsprojects/lite-test.vcproj b/vsprojects/lite-test.vcproj
deleted file mode 100644
index 8d17224..0000000
--- a/vsprojects/lite-test.vcproj
+++ /dev/null
@@ -1,333 +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="$(OutDir)\$(ProjectName)"
-			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="$(OutDir)\$(ProjectName)"
-			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\map_lite_unittest.pb.h"></File>
-			<File RelativePath="..\src\google\protobuf\map_lite_test_util.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\map_lite_unittest.pb.cc"></File>
-			<File RelativePath="..\src\google\protobuf\map_lite_test_util.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>
-		<File
-			RelativePath="..\src\google\protobuf\map_lite_unittest.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating map_lite_unittest.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/map_lite_unittest.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\map_lite_unittest.pb.h;google\protobuf\map_lite_unittest.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating map_lite_unittest.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/map_lite_unittest.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\map_lite_unittest.pb.h;google\protobuf\map_lite_unittest.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 4359e23..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="$(OutDir)\$(ProjectName)"
-			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="$(OutDir)\$(ProjectName)"
-			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 ad34249..0000000
--- a/vsprojects/readme.txt
+++ /dev/null
@@ -1,121 +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
-========================
-
-0) Check whether a gtest directory exists in the upper level directory. If
-   you checkout the code from github via "git clone", this gtest directory
-   won't exist and you won't be able to build the tests described below. To
-   avoid this problem consider downloading one of the release tar balls which
-   contains gtest already and copying the gest directory from there to your
-   protobuf directory:
-       https://github.com/google/protobuf/releases
-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 549f950..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="$(OutDir)\$(ProjectName)"
-			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="$(OutDir)\$(ProjectName)"
-			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 0d42949..0000000
--- a/vsprojects/tests.vcproj
+++ /dev/null
@@ -1,1109 +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="$(OutDir)\$(ProjectName)"
-			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="$(OutDir)\$(ProjectName)"
-			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\map_test_util_impl.h"></File>
-			<File RelativePath="..\src\google\protobuf\map_test_util.h"></File>
-			<File RelativePath="..\src\google\protobuf\arena_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\arenastring_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\arena_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\command_line_interface_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_bootstrap_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_plugin_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\importer_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_plugin_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\mock_code_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\parser_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\drop_unknown_fields_test.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\generated_message_reflection_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\printer_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\tokenizer_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\map_field_test.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\map_test.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\map_test_util.cc"
-				>
-			</File>
-			<File RelativePath="..\src\google\protobuf\arena_test_util.cc"></File>
-			<File
-				RelativePath="..\src\google\protobuf\message_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\no_field_presence_test.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\preserve_unknown_enum_test.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\proto3_arena_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\reflection_ops_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field_reflection_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\structurally_valid_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\strutil_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\testing\file.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\googletest.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\unknown_field_set_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_preserve_unknown_enum2.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\map_proto2_unittest.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\map_unittest.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_arena.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_custom_options.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_drop_unknown_fields.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_embed_optimize_for.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_empty.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_lite.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_public_lite.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_lite.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_mset.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_no_arena_import.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_no_arena.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_no_field_presence.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_no_generic_services.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_optimize_for.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_preserve_unknown_enum.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_proto3_arena.pb.cc"
-				>
-			</File>
-		</Filter>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_preserve_unknown_enum2.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_preserve_unknown_enum2.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum2.proto"
-					Outputs="google\protobuf\unittest_preserve_unknown_enum2.pb.h;google\protobuf\unittest_preserve_unknown_enum2.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_preserve_unknown_enum2.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum2.proto"
-					Outputs="google\protobuf\unittest_preserve_unknown_enum2.pb.h;google\protobuf\unittest_preserve_unknown_enum2.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\map_proto2_unittest.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating map_proto2_unittest.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/map_proto2_unittest.proto"
-					Outputs="google\protobuf\map_proto2_unittest.pb.h;google\protobuf\map_proto2_unittest.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating map_proto2_unittest.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/map_proto2_unittest.proto"
-					Outputs="google\protobuf\map_proto2_unittest.pb.h;google\protobuf\map_proto2_unittest.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\map_unittest.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating map_unittest.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/map_unittest.proto"
-					Outputs="google\protobuf\map_unittest.pb.h;google\protobuf\map_unittest.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating map_unittest.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/map_unittest.proto"
-					Outputs="google\protobuf\map_unittest.pb.h;google\protobuf\map_unittest.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"
-					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"
-					Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_arena.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_arena.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_arena.proto"
-					Outputs="google\protobuf\unittest_arena.pb.h;google\protobuf\unittest_arena.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_arena.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_arena.proto"
-					Outputs="google\protobuf\unittest_arena.pb.h;google\protobuf\unittest_arena.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"
-					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"
-					Outputs="google\protobuf\unittest_custom_options.pb.h;google\protobuf\unittest_custom_options.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_drop_unknown_fields.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_drop_unknown_fields.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_drop_unknown_fields.proto"
-					Outputs="google\protobuf\unittest_drop_unknown_fields.pb.h;google\protobuf\unittest_drop_unknown_fields.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_drop_unknown_fields.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_drop_unknown_fields.proto"
-					Outputs="google\protobuf\unittest_drop_unknown_fields.pb.h;google\protobuf\unittest_drop_unknown_fields.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"
-					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"
-					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_empty.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_empty.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_empty.proto"
-					Outputs="google\protobuf\unittest_empty.pb.h;google\protobuf\unittest_empty.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_empty.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_empty.proto"
-					Outputs="google\protobuf\unittest_empty.pb.h;google\protobuf\unittest_empty.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"
-					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"
-					Outputs="google\protobuf\unittest_import_lite.pb.h;google\protobuf\unittest_import_lite.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"
-					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"
-					Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.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"
-					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"
-					Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.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"
-					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"
-					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"
-					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"
-					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_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"
-					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"
-					Outputs="google\protobuf\unittest_lite.pb.h;google\protobuf\unittest_lite.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"
-					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"
-					Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_no_arena_import.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_arena_import.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena_import.proto"
-					Outputs="google\protobuf\unittest_no_arena_import.pb.h;google\protobuf\unittest_no_arena_import.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_arena_import.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena_import.proto"
-					Outputs="google\protobuf\unittest_no_arena_import.pb.h;google\protobuf\unittest_no_arena_import.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_no_arena.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_arena.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena.proto"
-					Outputs="google\protobuf\unittest_no_arena.pb.h;google\protobuf\unittest_no_arena.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_arena.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_arena.proto"
-					Outputs="google\protobuf\unittest_no_arena.pb.h;google\protobuf\unittest_no_arena.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_no_field_presence.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_field_presence.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_field_presence.proto"
-					Outputs="google\protobuf\unittest_no_field_presence.pb.h;google\protobuf\unittest_no_field_presence.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_field_presence.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_field_presence.proto"
-					Outputs="google\protobuf\unittest_no_field_presence.pb.h;google\protobuf\unittest_no_field_presence.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"
-					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"
-					Outputs="google\protobuf\unittest_no_generic_services.pb.h;google\protobuf\unittest_no_generic_services.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"
-					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"
-					Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_preserve_unknown_enum.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_preserve_unknown_enum.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum.proto"
-					Outputs="google\protobuf\unittest_preserve_unknown_enum.pb.h;google\protobuf\unittest_preserve_unknown_enum.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_preserve_unknown_enum.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_preserve_unknown_enum.proto"
-					Outputs="google\protobuf\unittest_preserve_unknown_enum.pb.h;google\protobuf\unittest_preserve_unknown_enum.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_proto3_arena.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_proto3_arena.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_proto3_arena.proto"
-					Outputs="google\protobuf\unittest_proto3_arena.pb.h;google\protobuf\unittest_proto3_arena.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_proto3_arena.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_proto3_arena.proto"
-					Outputs="google\protobuf\unittest_proto3_arena.pb.h;google\protobuf\unittest_proto3_arena.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<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"
-					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"
-					Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>